import { useEffect, useMemo, useRef } from "react"; import { Badge } from "@/components/ui/badge"; export type CodeFileName = "index.html" | "styles.css" | "script.js"; interface CodeStreamPanelProps { streamedHtml: string; activeFile: CodeFileName; onActiveFileChange: (next: CodeFileName) => void; generationLoading: boolean; generationStatus?: string | null; generationLogs: string[]; generationError?: string | null; } const FILE_ORDER: CodeFileName[] = ["index.html", "styles.css", "script.js"]; type HighlightTokenType = | "plain" | "comment" | "keyword" | "string" | "number" | "property" | "tag"; interface HighlightSegment { text: string; type: HighlightTokenType; } const TOKEN_CLASS: Record = { plain: "text-[#c9d1d9]", comment: "text-[#8b949e]", keyword: "text-[#ff7b72]", string: "text-[#a5d6ff]", number: "text-[#79c0ff]", property: "text-[#d2a8ff]", tag: "text-[#7ee787]", }; function tokenizeCode( code: string, pattern: RegExp, classify: (token: string) => HighlightSegment[], ): HighlightSegment[] { const segments: HighlightSegment[] = []; let lastIndex = 0; for (const match of code.matchAll(pattern)) { const matchIndex = match.index ?? 0; const token = match[0] ?? ""; if (matchIndex > lastIndex) { segments.push({ text: code.slice(lastIndex, matchIndex), type: "plain", }); } segments.push(...classify(token)); lastIndex = matchIndex + token.length; } if (lastIndex < code.length) { segments.push({ text: code.slice(lastIndex), type: "plain", }); } return segments; } function highlightHtmlTag(tagToken: string): HighlightSegment[] { const segments: HighlightSegment[] = []; let lastIndex = 0; for (const match of tagToken.matchAll(/"[^"]*"|'[^']*'/g)) { const matchIndex = match.index ?? 0; const token = match[0] ?? ""; if (matchIndex > lastIndex) { segments.push({ text: tagToken.slice(lastIndex, matchIndex), type: "tag", }); } segments.push({ text: token, type: "string", }); lastIndex = matchIndex + token.length; } if (lastIndex < tagToken.length) { segments.push({ text: tagToken.slice(lastIndex), type: "tag", }); } return segments; } function highlightHtml(code: string): HighlightSegment[] { return tokenizeCode( code, /|<\/?[a-zA-Z!][^>]*>/g, (token): HighlightSegment[] => { if (token.startsWith("