Skip to content

Commit

Permalink
devarea page added with two tools, issue
Browse files Browse the repository at this point in the history
  • Loading branch information
devvsakib committed Aug 3, 2024
1 parent fbf0804 commit 18345b4
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 11 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.0",
"react-icons": "^4.7.1",
"react-json-pretty": "^2.2.0",
"react-markdown": "^9.0.1",
"react-modal": "^3.16.1",
"react-router-dom": "^6.25.1",
Expand Down
72 changes: 72 additions & 0 deletions src/components/DevAreaTools/JSONFormatter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { useState } from 'react';
import { Input, Button, Alert } from 'antd';
import JSONPretty from 'react-json-pretty'; // You might need to install this library for pretty JSON output
import 'react-json-pretty/themes/monikai.css'; // Optional: import a theme for JSONPretty
import { toast } from 'sonner';

const JSONFormatter = () => {
const [jsonInput, setJsonInput] = useState('');
const [formattedJson, setFormattedJson] = useState(null);
const [error, setError] = useState('');

const handleFormat = () => {
try {
const parsedJson = JSON.parse(jsonInput);
setFormattedJson(parsedJson);
setError('');
} catch (err) {
setError('Invalid JSON format');
setFormattedJson(null);
}
};

const handleClear = () => {
setJsonInput('');
setFormattedJson(null);
setError('');
};

const handleCopy = () => {
if (formattedJson) {
navigator.clipboard.writeText(JSON.stringify(formattedJson, null, 2))
.then(() => {
toast.success('JSON copied to clipboard');
})
.catch(err => alert('Failed to copy JSON: ' + err));
} else {
alert('Nothing to copy');
}
};

return (
<div className='p-5'>
<h2 className='text-xl font-bold mb-4'>JSON Formatter</h2>
<Input.TextArea
value={jsonInput}
onChange={(e) => setJsonInput(e.target.value)}
placeholder="Paste your JSON here"
autoSize={{ minRows: 10 }}
className='mb-4 dark:bg-dark dark:text-white'
/>
<div className='mb-4'>
<Button onClick={handleFormat} type="primary" className='mr-2'>
Format JSON
</Button>
<Button onClick={handleClear} type="default">
Clear
</Button>
<Button onClick={handleCopy} type="default">
Copy to Clipboard
</Button>
</div>
{error && <Alert message="Error" description={error} type="error" className='mb-4' />}
{formattedJson && (
<div className='bg-dark p-4 rounded-md'>
<JSONPretty data={formattedJson} onCopy={(data) => navigator.clipboard.writeText(JSON.stringify(data, null, 2))} />
</div>
)}
</div>
);
};

export default JSONFormatter;
104 changes: 104 additions & 0 deletions src/components/DevAreaTools/MarkDownEditor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { useState } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { a11yDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { Input, Button } from 'antd';
import Layout from '../Layout/Layout';

const MarkDownEditor = () => {
const [content, setContent] = useState("");

const handleDownload = () => {
const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'document.md';
link.click();
URL.revokeObjectURL(url);
};

return (
<div className='grid md:grid-cols-2 gap-5 px-5 md:px-10 h-dvh overflow-y-scroll'>
<div>
<Input.TextArea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Enter markdown here"
autoSize={{ minRows: 20 }}
className='min-h-screen dark:bg-black text-sm md:text-base dark:text-white p-4 !outline-none placeholder:font-semibold'
/>
<Button
onClick={handleDownload}
type="primary"
className='mt-4'
>
Download Markdown
</Button>
</div>

<div className='bg-dark/40 p-5 rounded-md overflow-auto'>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
style={a11yDark}
language={match[1]}
PreTag="div"
{...props}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className} {...props}>
{children}
</code>
);
},
blockquote({ node, children }) {
return <blockquote className='bg-gray-100 p-4 pl-6 text-sm my-4 border-l-4 border-gray-300'>{children}</blockquote>;
},
li({ node, children }) {
return <li className='list-disc ml-4'>{children}</li>;
},
ul({ node, children }) {
return <ul className='list-disc ml-4 mb-2'>{children}</ul>;
},
ol({ node, children }) {
return <ol className='list-decimal ml-4 mb-2'>{children}</ol>;
},
img({ node, src, alt }) {
return <img src={src} alt={alt} className='mb-4 rounded-md' />;
},
h1({ node, children }) {
return <h1 className='text-3xl font-bold mt-6 mb-4'>{children}</h1>;
},
h2({ node, children }) {
return <h2 className='text-2xl font-semibold mt-5 mb-3'>{children}</h2>;
},
h3({ node, children }) {
return <h3 className='text-xl font-medium mt-4 mb-2'>{children}</h3>;
},
h4({ node, children }) {
return <h4 className='text-lg font-medium mt-3 mb-1'>{children}</h4>;
},
h5({ node, children }) {
return <h5 className='text-md font-medium mt-2 mb-1'>{children}</h5>;
},
h6({ node, children }) {
return <h6 className='text-sm font-medium mt-1 mb-1'>{children}</h6>;
}
}}
>
{content}
</ReactMarkdown>
</div>
</div>
);
};

export default MarkDownEditor;
5 changes: 5 additions & 0 deletions src/components/Header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ function Header({notice }) {
link: "/doc",
icon: <MdInsertDriveFile size="1.2rem" />,
},
{
name: "DevArea",
link: "/devarea",
icon: <MdStore size="1.2rem" />,
},
{
name: "Resources",
link: "/resources",
Expand Down
22 changes: 11 additions & 11 deletions src/components/Search/SearchInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ function SearchInput({ search, setSearch, setType }) {
className="flex items-center border border-primary gap-4 py-2 px-6 rounded-lg w-11/12 md:w-4/6"
>
<MdSearch className="text-gray text-2xl" />
<input
type="text"
id="searchbox"
value={search}
className="w-full text-sm md:text-base focus:outline-none placeholder:font-semibold bg-transparent custom-input"
placeholder="Search for errors"
onChange={(e) => {
setSearch(e.target.value);
setType("");
}}
/>
<input
type="text"
id="searchbox"
value={search}
className="w-full text-sm md:text-base focus:outline-none placeholder:font-semibold bg-transparent custom-input"
placeholder="Search for errors"
onChange={(e) => {
setSearch(e.target.value);
setType("");
}}
/>

<button
className={`focus:outline-none ${!search ? "hidden" : "block"}`}
Expand Down
12 changes: 12 additions & 0 deletions src/main.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Toaster } from 'sonner';
import {
createBrowserRouter,
RouterProvider,
Expand All @@ -11,6 +12,8 @@ import NotFound from "./pages/NotFound";
import DocList from "./pages/Doc";
import DocDetail from "./pages/Doc/single doc";
import Resources from "./pages/Resources";
import DevArea from "./pages/DevArea";
import DevTools from "./pages/DevArea/DevTools";

const router = createBrowserRouter(
[
Expand All @@ -30,6 +33,14 @@ const router = createBrowserRouter(
path: '/resources',
element: <Resources />
},
{
path: '/devarea',
element: <DevArea />
},
{
path: '/devarea/:tool',
element: <DevTools />
},
{
path: '/contributors',
element: <Contributors />
Expand All @@ -45,6 +56,7 @@ const router = createBrowserRouter(
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<BGShape />
<Toaster />
<RouterProvider router={router} />
</React.StrictMode>
);
18 changes: 18 additions & 0 deletions src/pages/DevArea/DevTools.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useParams } from "react-router-dom";
import Layout from "../../components/Layout/Layout";
import MarkDownEditor from "../../components/DevAreaTools/MarkDownEditor";
import JSONFormatter from "../../components/DevAreaTools/JSONFormatter";

const DevTools = () => {
const { tool } = useParams();

const tools = {
markdown: <MarkDownEditor />,
"json-formatter": <JSONFormatter />
}


return <Layout>{tools[tool]}</Layout>;
};

export default DevTools;
73 changes: 73 additions & 0 deletions src/pages/DevArea/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Link } from "react-router-dom";
import MainTitle from "../../components/Common/MainTitle";
import Layout from "../../components/Layout/Layout";
import { FaArrowRight } from "react-icons/fa";

const DevArea = () => {
const tools = [
{
name: "Markdown",
link: "/devarea/markdown",
isAvailable: true
},
{
name: "JSON Formatter",
link: "/devarea/json-formatter",
isAvailable: true
},
{
name: "Base64 Encoder/Decoder",
link: "/devarea/base64",
isAvailable: false
},
{
name: "JWT Decoder",
link: "/devarea/jwt",
isAvailable: false
},
{
name: "URL Encoder/Decoder",
link: "/devarea/url",
isAvailable: false
},
{
name: "XML Formatter",
link: "/devarea/xml-formatter",
isAvailable: false
},
{
name: "YAML Formatter",
link: "/devarea/yaml-formatter",
isAvailable: false
},
{
name: "CSV Formatter",
link: "/devarea/csv-formatter",
isAvailable: false
},
]
return <Layout>
<div className="px-5 md:px-10">
<MainTitle highlight={'DevArea'} />

<div className="grid grid-cols-4 gap-5">
{tools.map((tool, index) => (
tool.isAvailable ?
<Link to={tool.link} key={index}
className="capitalize group flex items-center justify-between bg-white/10 p-5 rounded-md">
{tool.name}
<FaArrowRight className="dark:text-white opacity-0 group-hover:opacity-100 -translate-x-10 group-hover:translate-x-0 transition duration-300" />
</Link>
:
<div key={index}
className="capitalize group flex items-center justify-between bg-white/10 p-5 rounded-md">
{tool.name}
</div>
))}
</div>

</div>
</Layout>;
};

export default DevArea;
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2740,6 +2740,13 @@ react-is@^18.2.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==

react-json-pretty@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-json-pretty/-/react-json-pretty-2.2.0.tgz#9ba907d2b08d87e90456d87b6025feeceb8f63cf"
integrity sha512-3UMzlAXkJ4R8S4vmkRKtvJHTewG4/rn1Q18n0zqdu/ipZbUPLVZD+QwC7uVcD/IAY3s8iNVHlgR2dMzIUS0n1A==
dependencies:
prop-types "^15.6.2"

react-lifecycles-compat@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
Expand Down

0 comments on commit 18345b4

Please sign in to comment.