From 69449662712adfe46962881d96235440b5bedffc Mon Sep 17 00:00:00 2001 From: Kabir <44284877+kabir0x23@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:46:54 +0530 Subject: [PATCH] feat: tool | code snippet --- package-lock.json | 49 ++++-- package.json | 2 + .../Tools/CodeSnippet/CodeSnippet.jsx | 153 ++++++++++++++++++ .../Tools/CodeSnippet/CodeSnippetElements.jsx | 136 ++++++++++++++++ .../Tools/CodeSnippets/CodeSnippets.jsx | 0 .../CodeSnippets/CodeSnippetsElements.jsx | 0 src/components/Tools/Tools.jsx | 4 +- src/components/Tools/ToolsRoute.jsx | 2 + 8 files changed, 333 insertions(+), 13 deletions(-) create mode 100644 src/components/Tools/CodeSnippet/CodeSnippet.jsx create mode 100644 src/components/Tools/CodeSnippet/CodeSnippetElements.jsx delete mode 100644 src/components/Tools/CodeSnippets/CodeSnippets.jsx delete mode 100644 src/components/Tools/CodeSnippets/CodeSnippetsElements.jsx diff --git a/package-lock.json b/package-lock.json index d0835038..f1206d0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,12 +27,14 @@ "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "jwt-decode": "^4.0.0", + "lucide-react": "^0.454.0", "moment": "^2.30.1", "path": "^0.12.7", "path-to-regexp": "^6.2.2", "react-calendar-heatmap": "^1.9.0", "react-chartjs-2": "^5.2.0", "react-chatbot-kit": "^2.2.2", + "react-codemirror2": "^8.0.0", "react-csv": "^2.2.2", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", @@ -6504,6 +6506,20 @@ "react-dom": ">=16.8.0" } }, + "node_modules/@uiw/react-codemirror/node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/@uiw/react-markdown-preview": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.1.tgz", @@ -8148,18 +8164,10 @@ } }, "node_modules/codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } + "version": "5.65.18", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.18.tgz", + "integrity": "sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA==", + "peer": true }, "node_modules/color-convert": { "version": "1.9.3", @@ -13458,6 +13466,14 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.454.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.454.0.tgz", + "integrity": "sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -16219,6 +16235,15 @@ "react-conditionally-render": "^1.0.2" } }, + "node_modules/react-codemirror2": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-8.0.0.tgz", + "integrity": "sha512-JIbhXoghvX0BrasIoCQvRxBPIU78plfjF1Buz0gaMFvZXwEDjkCYBkQhucoOtudQ7ikbB1jJUnmCsutElti7yA==", + "peerDependencies": { + "codemirror": "5.x", + "react": ">=15.5 <=18.x" + } + }, "node_modules/react-colorful": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", diff --git a/package.json b/package.json index b09053ec..0c7d1fb8 100644 --- a/package.json +++ b/package.json @@ -37,12 +37,14 @@ "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "jwt-decode": "^4.0.0", + "lucide-react": "^0.454.0", "moment": "^2.30.1", "path": "^0.12.7", "path-to-regexp": "^6.2.2", "react-calendar-heatmap": "^1.9.0", "react-chartjs-2": "^5.2.0", "react-chatbot-kit": "^2.2.2", + "react-codemirror2": "^8.0.0", "react-csv": "^2.2.2", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", diff --git a/src/components/Tools/CodeSnippet/CodeSnippet.jsx b/src/components/Tools/CodeSnippet/CodeSnippet.jsx new file mode 100644 index 00000000..13c2a8ee --- /dev/null +++ b/src/components/Tools/CodeSnippet/CodeSnippet.jsx @@ -0,0 +1,153 @@ +import React, { useState, useRef } from "react"; +import { + Container, + Settings, + BackgroundColorInput, + LanguageSelect, + ButtonGroup, + CopyButton, + ThemeToggle, + Wrapper, + CodeContainer, + EditorContainer, + Editor, +} from "./CodeSnippetElements"; +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { + solarizedlight, + coldarkDark, + atomDark, + prism, + materialLight, + materialDark, +} from "react-syntax-highlighter/dist/esm/styles/prism"; +import { Copy, Check, Sun, Moon } from "lucide-react"; + +const LANGUAGES = ["javascript", "typescript", "python", "java", "cpp", "csharp", "ruby", "swift", "kotlin", "rust"]; + +const THEMES = { + dark: [coldarkDark, atomDark, materialDark], + light: [solarizedlight, prism, materialLight], +}; + +const CodeSnippet = () => { + const [code, setCode] = useState(`const hello = () => { + console.log("Hello, world!"); +}; + +hello(); // Call the function`); + const [backgroundColor, setBackgroundColor] = useState("#1E1E1E"); + const [language, setLanguage] = useState("javascript"); + const [isDarkTheme, setIsDarkTheme] = useState(true); + const [themeIndex, setThemeIndex] = useState(0); + const [isCopied, setIsCopied] = useState(false); + const codeRef = useRef(null); + + const handleCopyCode = () => { + if (codeRef.current) { + navigator.clipboard + .writeText(code) + .then(() => { + setIsCopied(true); + setTimeout(() => setIsCopied(false), 2000); + }) + .catch((err) => console.error("Failed to copy:", err)); + } + }; + + const toggleTheme = () => { + setIsDarkTheme(!isDarkTheme); + setThemeIndex((prevIndex) => (prevIndex + 1) % (isDarkTheme ? THEMES.dark.length : THEMES.light.length)); + }; + + return ( + + + {/* Code Editor */} + + setCode(e.target.value)} // Update this line + style={{ + minHeight: "200px", + padding: "10px", + backgroundColor: "#1E1E1E", + color: "#FFF", + borderRadius: "8px", + outline: "none", + fontFamily: "'Fira Code', monospace", + fontSize: "14px", + lineHeight: "1.5", + overflowY: "auto", + }} + /> + + + {/* Settings and Syntax Highlighter */} +
+ + setLanguage(e.target.value)}> + {LANGUAGES?.map((lang) => ( + + ))} + + + setBackgroundColor(e.target.value)} + title="Change Background Color" + /> + + + + {isDarkTheme ? : } + + + + {isCopied ? : } + + + + + + + {code.trim() !== "" ? code : "No code provided."} + + +
+
+
+ ); +}; + +export default CodeSnippet; diff --git a/src/components/Tools/CodeSnippet/CodeSnippetElements.jsx b/src/components/Tools/CodeSnippet/CodeSnippetElements.jsx new file mode 100644 index 00000000..1d3f1130 --- /dev/null +++ b/src/components/Tools/CodeSnippet/CodeSnippetElements.jsx @@ -0,0 +1,136 @@ +import styled from "styled-components"; + +export const Wrapper = styled.div` + width: 100%; + display: flex; + justify-content: center; + padding: 20px 0; + margin-top: 100px; +`; + +export const Container = styled.div` + width: 100%; + max-width: 1400px; + background-color: #0e0e0e; + padding: 15px; + border-radius: 12px; + box-shadow: 0 4px 8px rgb(0 0 0 / 20%); + overflow: hidden; + display: flex; +`; + +export const EditorContainer = styled.div` + width: 100%; + max-width: 500px; + max-height: 700px; + position: relative; + background-color: #101010; + padding: 16px; + border-radius: 8px; + box-shadow: inset 0 2px 4px rgb(0 0 0 / 20%); +`; + +export const Editor = styled.textarea` + width: 100%; + color: #f8f8f2; + font-size: 16px; + padding: 12px; + height: 100%; + background-color: transparent; + font-family: "Fira Code", monospace; + outline: none; + border: none; + resize: none; + line-height: 1.6; + border-radius: 8px; + overflow: auto; +`; + +export const Settings = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + padding: 16px; + background-color: #121212; + border-bottom: 1px solid #333; +`; + +export const LanguageSelect = styled.select` + background-color: #1c1c1c; + color: #fff; + border: none; + padding: 8px 12px; + border-radius: 6px; + margin-right: 10px; + font-size: 14px; +`; + +export const BackgroundColorInput = styled.input` + width: 40px; + height: 40px; + border: none; + border-radius: 50%; + cursor: pointer; + margin-right: 10px; + + &::-webkit-color-swatch-wrapper { + padding: 0; + } + + &::-webkit-color-swatch { + border: none; + border-radius: 50%; + } +`; + +export const ButtonGroup = styled.div` + display: flex; + align-items: center; +`; + +export const ThemeToggle = styled.button` + background-color: #333; + color: #fff; + border: none; + padding: 8px; + border-radius: 6px; + margin-right: 10px; + display: flex; + align-items: center; + cursor: pointer; + transition: background-color 0.3s; + + &:hover { + background-color: #444; + } +`; + +export const CopyButton = styled.button` + background-color: #333; + color: #fff; + border: none; + padding: 8px; + border-radius: 6px; + display: flex; + align-items: center; + cursor: pointer; + transition: background-color 0.3s; + + &:hover { + background-color: #444; + } +`; + +export const CodeContainer = styled.div` + padding: 20px; + display: flex; + justify-content: center; + align-items: center; + max-width: 100%; + overflow: auto; + margin-top: 20px; + background-color: #171717; + border-radius: 8px; + box-shadow: 0 2px 4px rgb(0 0 0 / 20%); +`; diff --git a/src/components/Tools/CodeSnippets/CodeSnippets.jsx b/src/components/Tools/CodeSnippets/CodeSnippets.jsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/Tools/CodeSnippets/CodeSnippetsElements.jsx b/src/components/Tools/CodeSnippets/CodeSnippetsElements.jsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/Tools/Tools.jsx b/src/components/Tools/Tools.jsx index 7fbc8354..b58fa211 100644 --- a/src/components/Tools/Tools.jsx +++ b/src/components/Tools/Tools.jsx @@ -8,6 +8,7 @@ import { TbHash } from "react-icons/tb"; import HeadingBanner from "src/components/Common/HeadingBanner/HeadingBanner"; import { RiEarthFill } from "react-icons/ri"; import { FaGoogle, FaInternetExplorer } from "react-icons/fa"; +import { HiCode } from "react-icons/hi"; const Tools = () => { const tools = [ @@ -21,6 +22,7 @@ const Tools = () => { { name: "IP Info", link: "/tools/ipinfo", icon: }, { name: "Sub Generator", link: "/tools/subdomain-generator", icon: }, { name: "Markdown Editor", link: "/tools/markdown-editor", icon: }, + { name: "CodeSnippet", link: "/tools/code-snippet", icon: }, // {name: "Binary Exploits", link: "/tools/binaryexploitation", icon: ,}, // {name: "jwt Decoder", link: "/tools/jwtdecoder", icon: ,}, @@ -30,7 +32,7 @@ const Tools = () => { return ( - + {tools.slice(0, 1).map((tool, index) => { return ( diff --git a/src/components/Tools/ToolsRoute.jsx b/src/components/Tools/ToolsRoute.jsx index 49a88e1a..5b8f2e98 100644 --- a/src/components/Tools/ToolsRoute.jsx +++ b/src/components/Tools/ToolsRoute.jsx @@ -12,6 +12,7 @@ import GoogleDorks from "./GoogleDork/GoogleDorkMain"; import IPInfo from "src/components/Tools/IPInfo.jsx"; import SubdomainGenerator from "src/components/Tools/SubdomainGenerator.jsx"; import MarkdownEditor from "src/components/Tools/MarkdownEditor.jsx"; +import CodeSnippet from "src/components/Tools/CodeSnippet/CodeSnippet.jsx"; const ToolsRoutes = () => { return ( @@ -29,6 +30,7 @@ const ToolsRoutes = () => { } /> } /> } /> + } /> {/* }/> */} } />