From a1a8ac42a6d7f8b000af78df68c86d96d1229331 Mon Sep 17 00:00:00 2001 From: patanjalikr13 <42902972+patanjalikr13@users.noreply.github.com> Date: Thu, 23 Mar 2023 12:46:34 +0530 Subject: [PATCH] added download button, downlaod handler and necessary utility functions (#85) Co-authored-by: Patanjali Kumar --- components/Markdown/CodeBlock.tsx | 94 ++++++++++++++++++++----------- utils/app/data.ts | 41 ++++++++++++++ 2 files changed, 103 insertions(+), 32 deletions(-) diff --git a/components/Markdown/CodeBlock.tsx b/components/Markdown/CodeBlock.tsx index 6ff52b6..89d2d25 100644 --- a/components/Markdown/CodeBlock.tsx +++ b/components/Markdown/CodeBlock.tsx @@ -1,41 +1,71 @@ -import { FC, useState } from "react"; -import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; -import { oneDark, oneLight } from "react-syntax-highlighter/dist/cjs/styles/prism"; +import {FC, useState} from "react"; +import {Prism as SyntaxHighlighter} from "react-syntax-highlighter"; +import {oneDark, oneLight} from "react-syntax-highlighter/dist/cjs/styles/prism"; +import {IconDownload} from '@tabler/icons-react'; +import {generateRandomString, programmingLanguages} from '@/utils/app/data'; interface Props { - language: string; - value: string; - lightMode: "light" | "dark"; + language: string; + value: string; + lightMode: "light" | "dark"; } -export const CodeBlock: FC = ({ language, value, lightMode }) => { - const [buttonText, setButtonText] = useState("Copy code"); +export const CodeBlock: FC = ({language, value, lightMode}) => { + const [buttonText, setButtonText] = useState("Copy code"); - const copyToClipboard = () => { - navigator.clipboard.writeText(value).then(() => { - setButtonText("Copied!"); + const copyToClipboard = () => { + navigator.clipboard.writeText(value).then(() => { + setButtonText("Copied!"); - setTimeout(() => { - setButtonText("Copy code"); - }, 2000); - }); - }; + setTimeout(() => { + setButtonText("Copy code"); + }, 2000); + }); + }; + const downloadAsFile = () => { + const fileExtension = programmingLanguages[language] || '.file'; + const suggestedFileName = `file-${generateRandomString(3, true)}${fileExtension}`; + const fileName = window.prompt('Enter file name', suggestedFileName); - return ( -
- - {value} - + if(!fileName){ + // user pressed cancel on prompt + return; + } - -
- ); + const blob = new Blob([value], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = fileName; + link.href = url; + link.style.display = "none"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + return ( +
+
+ + +
+ + + {value} + +
+ ); }; diff --git a/utils/app/data.ts b/utils/app/data.ts index b85b53f..09f0690 100644 --- a/utils/app/data.ts +++ b/utils/app/data.ts @@ -21,3 +21,44 @@ export const importConversations = (conversations: Conversation[]) => { localStorage.setItem("conversationHistory", JSON.stringify(conversations)); localStorage.setItem("selectedConversation", JSON.stringify(conversations[conversations.length - 1])); }; + +interface languageMap { + [key: string]: string | undefined +} + +export const programmingLanguages: languageMap = { + 'javascript': '.js', + 'python': '.py', + 'java': '.java', + 'c': '.c', + 'cpp': '.cpp', + 'c++': '.cpp', + 'c#': '.cs', + 'ruby': '.rb', + 'php': '.php', + 'swift': '.swift', + 'objective-c': '.m', + 'kotlin': '.kt', + 'typescript': '.ts', + 'go': '.go', + 'perl': '.pl', + 'rust': '.rs', + 'scala': '.scala', + 'haskell': '.hs', + 'lua': '.lua', + 'shell': '.sh', + 'sql': '.sql', + 'html': '.html', + 'css': '.css' + // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component +}; + + +export const generateRandomString = (length: Number, lowercase=false) => { + const chars = "ABCDEFGHJKLMNPQRSTUVWXY3456789"; // excluding similar looking characters like Z, 2, I, 1, O, 0 + let result = ""; + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return lowercase ? result.toLowerCase() : result; +}