import { ChevronDownIcon, ChevronUpIcon, PaintBrushIcon, XMarkIcon, } from "@heroicons/react/24/outline"; import { ContextItemWithId } from "../../shims/typings"; import { getMarkdownLanguageTagForFile } from "../../shims/utils"; import React from "react"; import styled from "styled-components"; import { defaultBorderRadius, lightGray, vscEditorBackground } from ".."; import { getFontSize } from "../../util"; import { postToIde } from "../../util/ide"; import { WebviewIde } from "../../shims/webviewIde"; import FileIcon from "../FileIcon"; import HeaderButtonWithText from "../HeaderButtonWithText"; import StyledMarkdownPreview from "./StyledMarkdownPreview"; const PreviewMarkdownDiv = styled.div<{ borderColor?: string; }>` background-color: ${vscEditorBackground}; border-radius: ${defaultBorderRadius}; border: 0.5px solid ${(props) => props.borderColor || lightGray}; margin-top: 4px; margin-bottom: 4px; overflow: hidden; position: relative; & div { background-color: ${vscEditorBackground}; } `; const PreviewMarkdownHeader = styled.div` margin: 0; padding: 2px 6px; border-bottom: 0.5px solid ${lightGray}; word-break: break-all; font-size: ${getFontSize() - 2}px; display: flex; align-items: center; `; interface CodeSnippetPreviewProps { item: ContextItemWithId; onDelete?: () => void; onEdit?: () => void; borderColor?: string; editing?: boolean; } const StyledHeaderButtonWithText = styled(HeaderButtonWithText)<{ color?: string; }>` ${(props) => props.color && `background-color: ${props.color};`} `; const MAX_PREVIEW_HEIGHT = 300; // Pre-compile the regular expression outside of the function const backticksRegex = /`{3,}/gm; function CodeSnippetPreview(props: CodeSnippetPreviewProps) { const [collapsed, setCollapsed] = React.useState(true); const [hovered, setHovered] = React.useState(false); const fence = React.useMemo(() => { const backticks = props.item.content.match(backticksRegex); return backticks ? backticks.sort().at(-1) + "`" : "```"; }, [props.item.content]); const codeBlockRef = React.useRef(null); const codeBlockHeight = `${Math.min( MAX_PREVIEW_HEIGHT, codeBlockRef.current?.scrollHeight ?? // Best estimate of height I currently could find props.item.content.split("\n").length * 18 + 36, )}px`; return ( setHovered(true)} onMouseLeave={() => setHovered(false)} borderColor={props.borderColor} > { if (props.item.id.providerTitle === "file") { postToIde("showFile", { filepath: props.item.description, }); } else if (props.item.id.providerTitle === "code") { const lines = props.item.name .split("(")[1] .split(")")[0] .split("-"); new WebviewIde().showLines( props.item.description, parseInt(lines[0]) - 1, parseInt(lines[1]) - 1, ); } else { postToIde("showVirtualFile", { name: props.item.name, content: props.item.content, }); } }} >
{props.item.name}
{props.onEdit && ( { e.stopPropagation(); e.preventDefault(); props.onEdit(); }} {...(props.editing && { color: "#f0f4" })} > )} { e.stopPropagation(); props.onDelete(); }} >
{codeBlockRef.current?.scrollHeight > MAX_PREVIEW_HEIGHT && ( {collapsed ? ( setCollapsed(false)} /> ) : ( setCollapsed(true)} /> )} )}
); } export default CodeSnippetPreview;