feat(string coder) implementation

This commit is contained in:
lumither committed 2024-10-15 01:48:25 -07:00
1 parent b84f81611a
commit efdea9872f
7 files changed
+222 -11

No files matched your search

+20 -4
View File
@@ -1,24 +1,40 @@
'use client';
import React from 'react';
import ThemeSwitcher from '@/Components/ThemeSwitcher';
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 path = usePathname();
const currModule = searchPageName(path);
return (
<div>
<div className={ 'z-50' }>
<div
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={ 'flex flex-row items-center justify-between align-baseline' }>
<div className={ 'grid grid-cols-2 md:grid-cols-3 items-center justify-between' }>
<Link
className={ 'font-bold text-2xl' }
href={ '/' }
>
LMTLab
</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>
+4
View File
@@ -2,6 +2,10 @@
@tailwind components;
@tailwind utilities;
.text-weak {
@apply text-zinc-500 dark:text-zinc-400;
}
html.light {
--background: #ffffff;
--foreground: #171717;
+1 -7
View File
@@ -1,13 +1,7 @@
import { Card, CardBody } from '@nextui-org/card';
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() {
+56
View File
@@ -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'
}
};
+127
View File
@@ -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;
+12
View File
@@ -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'
}
];