diff --git a/frontend/components/editor/AIChat/ChatMessage.tsx b/frontend/components/editor/AIChat/ChatMessage.tsx
index caded21..8e93c17 100644
--- a/frontend/components/editor/AIChat/ChatMessage.tsx
+++ b/frontend/components/editor/AIChat/ChatMessage.tsx
@@ -19,6 +19,7 @@ export default function ChatMessage({
editorRef,
mergeDecorationsCollection,
setMergeDecorationsCollection,
+ selectFile,
}: MessageProps) {
// State for expanded message index
const [expandedMessageIndex, setExpandedMessageIndex] = useState<
@@ -115,8 +116,9 @@ export default function ChatMessage({
activeFileContent,
editorRef,
handleApplyCode,
+ selectFile,
mergeDecorationsCollection,
- setMergeDecorationsCollection
+ setMergeDecorationsCollection,
)
return (
diff --git a/frontend/components/editor/AIChat/index.tsx b/frontend/components/editor/AIChat/index.tsx
index 5d3ff69..ed2b6a9 100644
--- a/frontend/components/editor/AIChat/index.tsx
+++ b/frontend/components/editor/AIChat/index.tsx
@@ -19,6 +19,7 @@ export default function AIChat({
files,
templateType,
handleApplyCode,
+ selectFile,
mergeDecorationsCollection,
setMergeDecorationsCollection,
projectName,
@@ -225,6 +226,7 @@ export default function AIChat({
editorRef={editorRef}
mergeDecorationsCollection={mergeDecorationsCollection}
setMergeDecorationsCollection={setMergeDecorationsCollection}
+ selectFile={selectFile}
/>
))}
{isLoading && }
diff --git a/frontend/components/editor/AIChat/lib/chatUtils.ts b/frontend/components/editor/AIChat/lib/chatUtils.ts
index 1e3e956..70d50e3 100644
--- a/frontend/components/editor/AIChat/lib/chatUtils.ts
+++ b/frontend/components/editor/AIChat/lib/chatUtils.ts
@@ -1,4 +1,4 @@
-import { TFolder, TFile } from "@/lib/types"
+import { TFile, TFolder } from "@/lib/types"
import React from "react"
// Stringify content for chat message component
@@ -246,6 +246,8 @@ export const looksLikeCode = (text: string): boolean => {
// Add this new function after looksLikeCode function
export const isFilePath = (text: string): boolean => {
- // Match patterns like project/path/to/file.ext or project/path/to/file.ext (new file)
- return /^[a-zA-Z0-9_-]+\/[\w/-]+\.[a-zA-Z0-9]+(\s+\(new file\))?$/.test(text)
+ // Match patterns like next/styles/SignIn.module.css or path/to/file.ext (new file)
+ const pattern =
+ /^(?:[a-zA-Z0-9_.-]+\/)*[a-zA-Z0-9_.-]+\.[a-zA-Z0-9]+(\s+\(new file\))?$/
+ return pattern.test(text)
}
diff --git a/frontend/components/editor/AIChat/lib/markdownComponents.tsx b/frontend/components/editor/AIChat/lib/markdownComponents.tsx
index 0a6dcd3..36130d5 100644
--- a/frontend/components/editor/AIChat/lib/markdownComponents.tsx
+++ b/frontend/components/editor/AIChat/lib/markdownComponents.tsx
@@ -1,11 +1,13 @@
-import { Check, CornerUpLeft, X, FileText } from "lucide-react"
+import { useSocket } from "@/context/SocketContext"
+import { TTab } from "@/lib/types"
+import { Check, CornerUpLeft, FileText, X } from "lucide-react"
import monaco from "monaco-editor"
import { Components } from "react-markdown"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism"
import { Button } from "../../../ui/button"
import ApplyButton from "../ApplyButton"
-import { stringifyContent, isFilePath } from "./chatUtils"
+import { isFilePath, stringifyContent } from "./chatUtils"
// Create markdown components for chat message component
export const createMarkdownComponents = (
@@ -16,6 +18,7 @@ export const createMarkdownComponents = (
activeFileContent: string,
editorRef: any,
handleApplyCode: (mergedCode: string) => void,
+ selectFile: (tab: TTab) => void,
mergeDecorationsCollection?: monaco.editor.IEditorDecorationsCollection,
setMergeDecorationsCollection?: (collection: undefined) => void
): Components => ({
@@ -128,16 +131,58 @@ export const createMarkdownComponents = (
// Render markdown elements
p: ({ node, children, ...props }) => {
const content = stringifyContent(children)
-
+ const { socket } = useSocket()
+
if (isFilePath(content)) {
+ const isNewFile = content.endsWith("(new file)")
+ const filePath = (
+ isNewFile ? content.replace(" (new file)", "") : content
+ )
+ .split("/")
+ .filter((part, index) => index !== 0)
+ .join("/")
+
+ const handleFileClick = () => {
+ if (isNewFile) {
+ socket?.emit(
+ "createFile",
+ {
+ name: filePath,
+ },
+ (response: any) => {
+ if (response.success) {
+ const tab: TTab = {
+ id: filePath,
+ name: filePath.split("/").pop() || "",
+ saved: true,
+ type: "file",
+ }
+ selectFile(tab)
+ }
+ }
+ )
+ } else {
+ const tab: TTab = {
+ id: filePath,
+ name: filePath.split("/").pop() || "",
+ saved: true,
+ type: "file",
+ }
+ selectFile(tab)
+ }
+ }
+
return (
-
-
-
{content}
+
+
+ {content}
)
}
-
+
return renderMarkdownElement({ node, children, ...props })
},
h1: ({ node, children, ...props }) =>
diff --git a/frontend/components/editor/AIChat/types/index.ts b/frontend/components/editor/AIChat/types/index.ts
index 39ed75e..5eb7362 100644
--- a/frontend/components/editor/AIChat/types/index.ts
+++ b/frontend/components/editor/AIChat/types/index.ts
@@ -1,5 +1,5 @@
import { TemplateConfig } from "@/lib/templates"
-import { TFile, TFolder } from "@/lib/types"
+import { TFile, TFolder, TTab } from "@/lib/types"
import * as monaco from "monaco-editor"
import { Socket } from "socket.io-client"
@@ -60,6 +60,7 @@ export interface AIChatProps {
handleApplyCode: (mergedCode: string) => void
mergeDecorationsCollection?: monaco.editor.IEditorDecorationsCollection
setMergeDecorationsCollection?: (collection: undefined) => void
+ selectFile: (tab: TTab) => void
}
// Chat input props interface
@@ -115,6 +116,7 @@ export interface MessageProps {
editorRef: any
mergeDecorationsCollection?: monaco.editor.IEditorDecorationsCollection
setMergeDecorationsCollection?: (collection: undefined) => void
+ selectFile: (tab: TTab) => void
}
// Context tabs props interface
diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx
index 049b623..c470f17 100644
--- a/frontend/components/editor/index.tsx
+++ b/frontend/components/editor/index.tsx
@@ -1288,6 +1288,7 @@ export default function CodeEditor({
handleApplyCode={handleApplyCode}
mergeDecorationsCollection={mergeDecorationsCollection}
setMergeDecorationsCollection={setMergeDecorationsCollection}
+ selectFile={selectFile}
/>
>