feat(string coder) implementation
This commit is contained in:
1 parent
b84f81611a
commit
efdea9872f
7 files changed
+222
-11
No files matched your search
+20
-4
@@ -1,24 +1,40 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ThemeSwitcher from '@/Components/ThemeSwitcher';
|
import ThemeSwitcher from '@/Components/ThemeSwitcher';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { urlList } from '@/app/urlList';
|
||||||
|
|
||||||
|
const searchPageName = (url: string) => {
|
||||||
|
const page = urlList.find((it) => it.url === url);
|
||||||
|
|
||||||
|
return page && page.name;
|
||||||
|
};
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
|
const path = usePathname();
|
||||||
|
const currModule = searchPageName(path);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={ 'z-50' }>
|
||||||
<div
|
<div
|
||||||
className={ 'h-16 fixed backdrop-blur w-full z-50 transition-colors border-b-[1px] border-neutral-200 dark:border-neutral-700' }
|
className={ 'h-16 fixed backdrop-blur w-full z-50 transition-colors border-b-[1px] border-neutral-200 dark:border-neutral-700' }
|
||||||
>
|
>
|
||||||
|
|
||||||
<div className={ 'p-3 px-5' }>
|
<div className={ 'p-3 px-5' }>
|
||||||
<div className={ 'flex flex-row items-center justify-between align-baseline' }>
|
<div className={ 'grid grid-cols-2 md:grid-cols-3 items-center justify-between' }>
|
||||||
<Link
|
<Link
|
||||||
className={ 'font-bold text-2xl' }
|
className={ 'font-bold text-2xl' }
|
||||||
href={ '/' }
|
href={ '/' }
|
||||||
>
|
>
|
||||||
LMTLab
|
LMTLab
|
||||||
</Link>
|
</Link>
|
||||||
<ThemeSwitcher />
|
<p className={ 'hidden md:block text-2xl text-weak justify-self-center' }>
|
||||||
|
{ currModule }
|
||||||
|
</p>
|
||||||
|
<div className={ 'justify-self-end' }>
|
||||||
|
<ThemeSwitcher />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
.text-weak {
|
||||||
|
@apply text-zinc-500 dark:text-zinc-400;
|
||||||
|
}
|
||||||
|
|
||||||
html.light {
|
html.light {
|
||||||
--background: #ffffff;
|
--background: #ffffff;
|
||||||
--foreground: #171717;
|
--foreground: #171717;
|
||||||
|
|||||||
+1
-7
@@ -1,13 +1,7 @@
|
|||||||
import { Card, CardBody } from '@nextui-org/card';
|
import { Card, CardBody } from '@nextui-org/card';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { urlList } from '@/app/urlList';
|
||||||
|
|
||||||
const urlList = [
|
|
||||||
{
|
|
||||||
name: 'Json Parser',
|
|
||||||
desc: 'Parse a Json file, with formatter and syntax highlighting',
|
|
||||||
url: '/jsonparser'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { enc, MD5, SHA1, SHA256, SHA512 } from 'crypto-js';
|
||||||
|
|
||||||
|
export const hashAlgorithms = {
|
||||||
|
'SHA-1': (input: string) => {
|
||||||
|
return SHA1(input);
|
||||||
|
},
|
||||||
|
'SHA-256': (input: string) => {
|
||||||
|
return SHA256(input);
|
||||||
|
},
|
||||||
|
'SHA-512': (input: string) => {
|
||||||
|
return SHA512(input);
|
||||||
|
},
|
||||||
|
'MD5': (input: string) => {
|
||||||
|
return MD5(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeAlgorithms = {
|
||||||
|
'Base64': (input: string) => {
|
||||||
|
const wordArray = enc.Utf8.parse(input);
|
||||||
|
return enc.Base64.stringify(wordArray);
|
||||||
|
},
|
||||||
|
'URI': (input: string) => {
|
||||||
|
return encodeURI(input).toString();
|
||||||
|
},
|
||||||
|
'URI Component': (input: string) => {
|
||||||
|
return encodeURIComponent(input).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeAlgorithms = {
|
||||||
|
'Base64': (input: string) => {
|
||||||
|
return enc.Base64.parse(input).toString(enc.Utf8);
|
||||||
|
},
|
||||||
|
'URI': (input: string) => {
|
||||||
|
return decodeURI(input).toString();
|
||||||
|
},
|
||||||
|
'URI Component': (input: string) => {
|
||||||
|
return decodeURIComponent(input).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const algorithms = {
|
||||||
|
'hash': {
|
||||||
|
list: hashAlgorithms,
|
||||||
|
color: 'primary'
|
||||||
|
},
|
||||||
|
'encode': {
|
||||||
|
list: encodeAlgorithms,
|
||||||
|
color: 'secondary'
|
||||||
|
},
|
||||||
|
'decode': {
|
||||||
|
list: decodeAlgorithms,
|
||||||
|
color: 'success'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Button, Textarea } from '@nextui-org/react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { HiOutlineBackspace, HiOutlineDuplicate } from 'react-icons/hi';
|
||||||
|
import { algorithms } from '@/app/strcoder/algorithms';
|
||||||
|
import { useTheme } from 'next-themes';
|
||||||
|
|
||||||
|
type ButtonColor = 'primary' | 'secondary' | 'success' | 'default' | 'warning' | 'danger' | undefined;
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
const [ input, setInput ] = useState('');
|
||||||
|
const [ output, setOutput ] = useState('');
|
||||||
|
const { theme } = useTheme();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={ 'p-5 px-10 lg:p-20 h-full w-full' }
|
||||||
|
>
|
||||||
|
<div className={ 'flex flex-col gap-4 w-full' }>
|
||||||
|
<div
|
||||||
|
className={ 'h-full w-full relative' }
|
||||||
|
>
|
||||||
|
<Textarea
|
||||||
|
variant={ 'faded' }
|
||||||
|
label={ 'Input' }
|
||||||
|
value={ input }
|
||||||
|
onValueChange={ setInput }
|
||||||
|
/>
|
||||||
|
<div className={ 'flex flex-row-reverse absolute bottom-4 right-4 z-10' }>
|
||||||
|
<Button
|
||||||
|
variant={ 'light' }
|
||||||
|
isIconOnly
|
||||||
|
aria-label={ 'copy to clipboard' }
|
||||||
|
onClick={ () => {
|
||||||
|
navigator.clipboard.writeText(input);
|
||||||
|
toast.success('Copied to Clipboard');
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
<HiOutlineDuplicate size={ 20 } />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={ 'light' }
|
||||||
|
isIconOnly
|
||||||
|
aria-label={ 'clear input' }
|
||||||
|
onClick={ () => {
|
||||||
|
setInput('');
|
||||||
|
setOutput('');
|
||||||
|
toast.success('Input Cleared');
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
<HiOutlineBackspace size={ 20 } />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className={ 'text-center text-xl font-bold' }>Algorithms</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<ul className={ 'flex flex-col gap-6 w-full mb-4' }>
|
||||||
|
{
|
||||||
|
Object.entries(algorithms).map(([ category, list ]) => (
|
||||||
|
<li key={ category } className={ 'space-y-2' }>
|
||||||
|
<p className={ 'font-bold' }>{ category.toUpperCase() }</p>
|
||||||
|
<ul className={ 'flex flex-row flex-wrap gap-4 w-full' }>
|
||||||
|
{
|
||||||
|
Object.entries(list.list).map(([ key, value ]) => (
|
||||||
|
<li key={ key }>
|
||||||
|
<Button
|
||||||
|
variant={ theme === 'light' ? 'flat' : 'solid' }
|
||||||
|
aria-label={ `${ category } algorithm ${ key }` }
|
||||||
|
color={ list.color as ButtonColor }
|
||||||
|
onClick={ () => {
|
||||||
|
try {
|
||||||
|
setOutput((value as (input: string) => string)(input));
|
||||||
|
toast.success('Operation Succeed');
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(`Operation Failed: ${ error }`, {
|
||||||
|
autoClose: 5000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
{ key }
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={ 'h-full w-full relative' }
|
||||||
|
>
|
||||||
|
<Textarea
|
||||||
|
readOnly
|
||||||
|
variant={ 'faded' }
|
||||||
|
label={ 'Output' }
|
||||||
|
value={ output }
|
||||||
|
/>
|
||||||
|
<div className={ 'flex flex-row-reverse absolute bottom-4 right-4 z-10' }>
|
||||||
|
<Button
|
||||||
|
variant={ 'light' }
|
||||||
|
isIconOnly
|
||||||
|
aria-label={ 'copy to clipboard' }
|
||||||
|
onClick={ () => {
|
||||||
|
navigator.clipboard.writeText(output);
|
||||||
|
toast.success('Copied to Clipboard');
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
<HiOutlineDuplicate size={ 20 } />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export const urlList = [
|
||||||
|
{
|
||||||
|
name: 'Json Parser',
|
||||||
|
desc: 'Parse a Json file, with formatter and syntax highlighting',
|
||||||
|
url: '/jsonparser'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'String Coder',
|
||||||
|
desc: 'String encoding & decoding, hashing',
|
||||||
|
url: '/strcoder'
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@monaco-editor/react": "^4.6.0",
|
"@monaco-editor/react": "^4.6.0",
|
||||||
"@nextui-org/react": "^2.4.8",
|
"@nextui-org/react": "^2.4.8",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
"framer-motion": "^11.11.0",
|
"framer-motion": "^11.11.0",
|
||||||
"next": "14.2.14",
|
"next": "14.2.14",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"react-toastify": "^10.0.6"
|
"react-toastify": "^10.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
|||||||
Reference in new issue
Block a user