feat: Add code download functionality

Adds a new "Download Code" button to the code block component, allowing users to download the code displayed for offline use.

This feature enhances user convenience and provides a more versatile experience for exploring and utilizing code snippets.
This commit is contained in:
n4ze3m
2024-10-26 15:37:02 +05:30
parent a2f9002b81
commit 9cc309e9fd
18 changed files with 82 additions and 33 deletions

View File

@@ -1,5 +1,6 @@
import { programmingLanguages } from "@/utils/langauge-extension"
import { Tooltip, Modal } from "antd"
import { CheckIcon, ClipboardIcon, EyeIcon, Maximize2Icon } from "lucide-react"
import { CheckIcon, ClipboardIcon, DownloadIcon } from "lucide-react"
import { FC, useState } from "react"
import { useTranslation } from "react-i18next"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
@@ -23,30 +24,36 @@ export const CodeBlock: FC<Props> = ({ language, value }) => {
}, 4000)
}
const handlePreview = () => {
setPreviewVisible(true)
}
const handlePreviewClose = () => {
setPreviewVisible(false)
}
const handleDownload = () => {
const blob = new Blob([value], { type: "text/plain" })
const url = window.URL.createObjectURL(blob)
const a = document.createElement("a")
a.href = url
a.download = `code_${new Date().toISOString().replace(/[:.]/g, "-")}.${programmingLanguages[language] || language}`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
window.URL.revokeObjectURL(url)
}
return (
<>
<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">
<span className="text-xs lowercase text-gray-200">{language}</span>
<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>
)}
<div className="flex items-center gap-2">
<Tooltip title={t("downloadCode")}>
<button
onClick={handleDownload}
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">
<DownloadIcon className="h-4 w-4" />
</button>
</Tooltip>
<Tooltip title={t("copyToClipboard")}>
<button
onClick={handleCopy}

View File

@@ -54,14 +54,14 @@ export default function OptionLayout({
if (confirm) {
const db = new PageAssitDatabase()
await db.deleteAllChatHistory()
queryClient.invalidateQueries({
await queryClient.invalidateQueries({
queryKey: ["fetchChatHistory"]
})
clearChat()
}
}}
className="text-gray-600 hover:text-gray-800 dark:text-gray-300 dark:hover:text-gray-100">
<EraserIcon className="size-5" />
<EraserIcon className="size-5" />
</button>
</Tooltip>
</div>

View File

@@ -61,10 +61,10 @@ export const PlaygroundChat = () => {
)}
</div>
{!isAtBottom && (
<div className="fixed md:bottom-40 bottom-36 z-20 left-0 right-0 flex justify-center">
<div className="fixed bottom-36 z-20 left-0 right-0 flex justify-center">
<button
onClick={scrollToBottom}
className="bg-gray-100 border dark:border-gray-700 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-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full pointer-events-auto">
<ChevronDown className="size-4 text-gray-600 dark:text-gray-300" />
</button>
</div>