feat: Add HTML preview to code blocks

Adds an HTML preview feature to the code block component, allowing users to view the rendered output of their HTML code snippets. This improves the user experience by providing a more interactive and informative way to understand the code.
This commit is contained in:
n4ze3m 2024-10-19 23:54:09 +05:30
parent fd5339d90a
commit 7be993c057
2 changed files with 53 additions and 14 deletions

View File

@ -1,6 +1,6 @@
import { Tooltip } from "antd" import { Tooltip, Modal } from "antd"
import { CheckIcon, ClipboardIcon } from "lucide-react" import { CheckIcon, ClipboardIcon, EyeIcon, Maximize2Icon } from "lucide-react"
import { FC, useState } from "react" import { FC, useState } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter" import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism" import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism"
@ -10,26 +10,47 @@ interface Props {
value: string value: string
} }
export const CodeBlock: FC<Props> =({ language, value }) => { export const CodeBlock: FC<Props> = ({ language, value }) => {
const [isBtnPressed, setIsBtnPressed] = useState(false) const [isBtnPressed, setIsBtnPressed] = useState(false)
const [previewVisible, setPreviewVisible] = useState(false)
const { t } = useTranslation("common") const { t } = useTranslation("common")
const handleCopy = () => {
navigator.clipboard.writeText(value)
setIsBtnPressed(true)
setTimeout(() => {
setIsBtnPressed(false)
}, 4000)
}
const handlePreview = () => {
setPreviewVisible(true)
}
const handlePreviewClose = () => {
setPreviewVisible(false)
}
return ( return (
<> <>
<div className="code relative text-base font-sans codeblock bg-zinc-950 rounded-md overflow-hidden"> <div className="code relative text-base font-sans codeblock bg-zinc-950 rounded-md overflow-hidden">
<div className="flex bg-gray-800 items-center justify-between py-1.5 px-4"> <div className="flex bg-gray-800 items-center justify-between py-1.5 px-4">
<span className="text-xs lowercase text-gray-200">{language}</span> <span className="text-xs lowercase text-gray-200">{language}</span>
<div className="flex items-center"> <div className="flex items-center">
{language.toLowerCase() === "html" && (
<Tooltip title={t("preview")}>
<button
onClick={handlePreview}
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-200 hover:bg-gray-700 hover:text-gray-100 focus:outline-none">
<EyeIcon className="h-4 w-4" />
</button>
</Tooltip>
)}
<Tooltip title={t("copyToClipboard")}> <Tooltip title={t("copyToClipboard")}>
<button <button
onClick={() => { onClick={handleCopy}
navigator.clipboard.writeText(value) className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-200 hover:bg-gray-700 hover:text-gray-100 focus:outline-none">
setIsBtnPressed(true)
setTimeout(() => {
setIsBtnPressed(false)
}, 4000)
}}
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-200 hover:bg-gray-700 hover:text-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 focus:ring-offset-gray-100">
{!isBtnPressed ? ( {!isBtnPressed ? (
<ClipboardIcon className="h-4 w-4" /> <ClipboardIcon className="h-4 w-4" />
) : ( ) : (
@ -61,6 +82,24 @@ export const CodeBlock: FC<Props> =({ language, value }) => {
{value} {value}
</SyntaxHighlighter> </SyntaxHighlighter>
</div> </div>
{previewVisible && (
<Modal
open={previewVisible}
onCancel={handlePreviewClose}
footer={null}
width="80%"
zIndex={999999}
centered
bodyStyle={{ padding: 0 }}>
<div className="relative w-full h-[80vh]">
<iframe
srcDoc={value}
title="HTML Preview"
className="w-full h-full"
/>
</div>
</Modal>
)}
</> </>
) )
} }

View File

@ -61,7 +61,7 @@ export const PlaygroundChat = () => {
)} )}
</div> </div>
{!isAtBottom && ( {!isAtBottom && (
<div className="fixed md:bottom-44 bottom-36 z-[9999999] left-0 right-0 flex justify-center"> <div className="fixed md:bottom-44 bottom-36 z-[99999] left-0 right-0 flex justify-center">
<button <button
onClick={scrollToBottom} onClick={scrollToBottom}
className="bg-gray-100 dark:bg-gray-800 p-1 rounded-full shadow-md hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200"> className="bg-gray-100 dark:bg-gray-800 p-1 rounded-full shadow-md hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200">