feat: tools normalized

This commit is contained in:
Ibrahima G. Coulibaly
2024-06-22 22:06:16 +01:00
parent 17ba68be34
commit 23f50ffead
36 changed files with 2625 additions and 1045 deletions

View File

@@ -26,12 +26,7 @@
"ecmaVersion": 11,
"sourceType": "module"
},
"plugins": [
"react",
"react-hooks",
"@typescript-eslint",
"tailwindcss"
],
"plugins": ["react", "react-hooks", "@typescript-eslint", "tailwindcss"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",

View File

@@ -3,7 +3,7 @@ name: CI
on:
push:
branches:
- main # or the branch you want to trigger the workflow on
- main # or the branch you want to trigger the workflow on
pull_request:
branches:
- main
@@ -19,7 +19,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18' # Specify the Node.js version you want to use
node-version: '18' # Specify the Node.js version you want to use
- name: Install dependencies
run: npm install
@@ -42,4 +42,3 @@ jobs:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
timeout-minutes: 1

113
.idea/workspace.xml generated
View File

@@ -4,15 +4,43 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="chore: idea config">
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: react helmet">
<change afterPath="$PROJECT_DIR$/src/pages/images/imageTools.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/meta.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/images/png/pngTools.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/string/split/meta.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/string/stringTools.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/tools/defineTool.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/tools/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.eslintrc" beforeDir="false" afterPath="$PROJECT_DIR$/.eslintrc" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.github/workflows/ci.yml" beforeDir="false" afterPath="$PROJECT_DIR$/.github/workflows/ci.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/omni-tools.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/omni-tools.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Readme.md" beforeDir="false" afterPath="$PROJECT_DIR$/Readme.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/ToolLayout.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolLayout.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.vitest/setup.ts" beforeDir="false" afterPath="$PROJECT_DIR$/.vitest/setup.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pnpm-lock.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pnpm-lock.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/postcss.config.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/postcss.config.mjs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/App.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/App.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/Loading.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Loading.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/Navbar/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Navbar/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/ToolHeader.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolHeader.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/input/ToolTextInput.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/input/ToolTextInput.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/config/routesConfig.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/config/routesConfig.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/useDebounce.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/useDebounce.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/usePrevious.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/usePrevious.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/useTimeout.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/useTimeout.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/useUpdateEffect.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/useUpdateEffect.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/home/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/home/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/ImagesConfig.tsx" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/png/PngConfig.tsx" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/png/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/string/StringConfig.tsx" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/string/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/string/split/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/split/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tailwind.config.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/tailwind.config.mjs" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -41,32 +69,32 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;ASKED_ADD_EXTERNAL_FILES&quot;: &quot;true&quot;,
&quot;ASKED_SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;C:/Users/HP/IdeaProjects/omni-tools/public&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;npm.dev.executor&quot;: &quot;Run&quot;,
&quot;npm.prebuild.executor&quot;: &quot;Run&quot;,
&quot;prettierjs.PrettierConfiguration.Package&quot;: &quot;C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\prettier&quot;,
&quot;project.structure.last.edited&quot;: &quot;Problems&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;settings.typescriptcompiler&quot;,
&quot;ts.external.directory.path&quot;: &quot;C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ASKED_ADD_EXTERNAL_FILES": "true",
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"git-widget-placeholder": "main",
"ignore.virus.scanning.warn.message": "true",
"kotlin-language-version-configured": "true",
"last_opened_file_path": "C:/Users/HP/IdeaProjects/omni-tools/src/pages/string/split",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"npm.dev.executor": "Run",
"npm.prebuild.executor": "Run",
"prettierjs.PrettierConfiguration.Package": "C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\prettier",
"project.structure.last.edited": "Problems",
"project.structure.proportion": "0.0",
"project.structure.side.proportion": "0.2",
"settings.editor.selected.configurable": "settings.typescriptcompiler",
"ts.external.directory.path": "C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
"vue.rearranger.settings.migration": "true"
}
}</component>
}]]></component>
<component name="ReactDesignerToolWindowState">
<option name="myId2Visible">
<map>
@@ -78,11 +106,15 @@
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\pages\string\split" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\pages\images" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\public" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\assets" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\pages\string" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\pages\images" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\pages\images\png\change-colors-in-png" />
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\tools" />
</key>
</component>
<component name="RunManager" selected="npm.dev">
@@ -129,7 +161,7 @@
<workItem from="1719006887776" duration="7000" />
<workItem from="1719006951159" duration="2377000" />
<workItem from="1719021128819" duration="3239000" />
<workItem from="1719083989394" duration="1047000" />
<workItem from="1719083989394" duration="6308000" />
</task>
<task id="LOCAL-00001" summary="feat: use vite and ts">
<option name="closed" value="true" />
@@ -299,7 +331,15 @@
<option name="project" value="LOCAL" />
<updated>1719024346455</updated>
</task>
<option name="localTasksCounter" value="22" />
<task id="LOCAL-00022" summary="feat: react helmet">
<option name="closed" value="true" />
<created>1719085085537</created>
<option name="number" value="00022" />
<option name="presentableId" value="LOCAL-00022" />
<option name="project" value="LOCAL" />
<updated>1719085085537</updated>
</task>
<option name="localTasksCounter" value="23" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@@ -338,7 +378,8 @@
<MESSAGE value="test: init" />
<MESSAGE value="chore: remove prebuild" />
<MESSAGE value="chore: idea config" />
<option name="LAST_COMMIT_MESSAGE" value="chore: idea config" />
<MESSAGE value="feat: react helmet" />
<option name="LAST_COMMIT_MESSAGE" value="feat: react helmet" />
</component>
<component name="XSLT-Support.FileAssociations.UIState">
<expand />

View File

@@ -1 +1 @@
import '@testing-library/jest-dom/vitest'
import '@testing-library/jest-dom/vitest';

View File

@@ -1,13 +1,13 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Omni Tools</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Omni Tools</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

3083
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,4 +3,4 @@ export default {
tailwindcss: {},
autoprefixer: {}
}
}
};

View File

@@ -7,9 +7,14 @@ import { ThemeProvider } from '@mui/material';
import theme from '../config/muiConfig';
import { CustomSnackBarProvider } from '../contexts/CustomSnackBarContext';
import { SnackbarProvider } from 'notistack';
import { tools } from '../tools';
const AppRoutes = () => {
return useRoutes(routesConfig);
const updatedRoutesConfig = [...routesConfig];
tools.forEach((tool) => {
updatedRoutesConfig.push({ path: tool.path, element: tool.component() });
});
return useRoutes(updatedRoutesConfig);
};
function App() {

View File

@@ -1,7 +1,7 @@
import Typography from '@mui/material/Typography'
import { useState } from 'react'
import Box from '@mui/material/Box'
import { useTimeout } from '../hooks'
import Typography from '@mui/material/Typography';
import { useState } from 'react';
import Box from '@mui/material/Box';
import { useTimeout } from '../hooks';
export type FuseLoadingProps = {
delay?: number;
@@ -12,16 +12,15 @@ export type FuseLoadingProps = {
* FuseLoading displays a loading state with an optional delay
*/
function FuseLoading(props: FuseLoadingProps) {
const { delay = 0, className } = props
const [showLoading, setShowLoading] = useState(!delay)
const { delay = 0, className } = props;
const [showLoading, setShowLoading] = useState(!delay);
useTimeout(() => {
setShowLoading(true)
}, delay)
setShowLoading(true);
}, delay);
return (
<div
>
<div>
<Typography
className="-mb-16 text-13 font-medium sm:text-20"
color="text.secondary"
@@ -41,7 +40,7 @@ function FuseLoading(props: FuseLoadingProps) {
<div className="bounce3" />
</Box>
</div>
)
);
}
export default FuseLoading
export default FuseLoading;

View File

@@ -4,22 +4,41 @@ import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import {Link, useNavigate} from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import githubIcon from '../../assets/github-mark.png'; // Adjust the path to your GitHub icon
const Navbar: React.FC = () => {
const navigate = useNavigate();
return (
<AppBar position="static" style={{backgroundColor: 'white', color: 'black'}}>
<AppBar
position="static"
style={{ backgroundColor: 'white', color: 'black' }}
>
<Toolbar>
<Typography onClick={() => navigate('/')} fontSize={20}
sx={{flexGrow: 1, cursor: 'pointer'}} color={'primary'}>OmniTools</Typography>
<Typography
onClick={() => navigate('/')}
fontSize={20}
sx={{ flexGrow: 1, cursor: 'pointer' }}
color={'primary'}
>
OmniTools
</Typography>
<Button color="inherit">
<Link to="/features" style={{textDecoration: 'none', color: 'inherit'}}>Features</Link>
<Link
to="/features"
style={{ textDecoration: 'none', color: 'inherit' }}
>
Features
</Link>
</Button>
<Button color="inherit">
<Link to="/about-us" style={{textDecoration: 'none', color: 'inherit'}}>About Us</Link>
<Link
to="/about-us"
style={{ textDecoration: 'none', color: 'inherit' }}
>
About Us
</Link>
</Button>
<IconButton
@@ -28,7 +47,11 @@ const Navbar: React.FC = () => {
target="_blank"
rel="noopener noreferrer"
>
<img src={githubIcon} alt="GitHub" style={{height: '24px', marginRight: '8px'}}/>
<img
src={githubIcon}
alt="GitHub"
style={{ height: '24px', marginRight: '8px' }}
/>
<Typography variant="button">Star us</Typography>
</IconButton>
</Toolbar>

View File

@@ -1,18 +1,22 @@
import {Box, Stack} from "@mui/material";
import Typography from "@mui/material/Typography";
import textImage from '../assets/text.png'
import { Box, Stack } from '@mui/material';
import Typography from '@mui/material/Typography';
import textImage from '../assets/text.png';
interface ToolHeaderProps {
title: string;
description: string;
}
export default function ToolHeader({title, description}: ToolHeaderProps) {
return (<Stack direction={'row'} alignItems={'center'} spacing={2} mt={4}>
<Box>
<Typography mb={2} fontSize={30} color={'primary'}>{title}</Typography>
<Typography fontSize={20}>{description}</Typography>
</Box>
<img width={'20%'} src={textImage}/>
</Stack>)
export default function ToolHeader({ title, description }: ToolHeaderProps) {
return (
<Stack direction={'row'} alignItems={'center'} spacing={2} mt={4}>
<Box>
<Typography mb={2} fontSize={30} color={'primary'}>
{title}
</Typography>
<Typography fontSize={20}>{description}</Typography>
</Box>
<img width={'20%'} src={textImage} />
</Stack>
);
}

View File

@@ -1,14 +1,18 @@
import { Box, Stack, TextField } from '@mui/material'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import PublishIcon from '@mui/icons-material/Publish'
import ContentPasteIcon from '@mui/icons-material/ContentPaste'
import React from 'react'
import { Box, Stack, TextField } from '@mui/material';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import PublishIcon from '@mui/icons-material/Publish';
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import React from 'react';
export default function ToolTextInput({ value, onChange, title = 'Input text' }: {
export default function ToolTextInput({
value,
onChange,
title = 'Input text'
}: {
title?: string;
value: string
onChange: (value: string) => void
value: string;
onChange: (value: string) => void;
}) {
return (
<Box>
@@ -27,5 +31,5 @@ export default function ToolTextInput({ value, onChange, title = 'Input text' }:
<Button startIcon={<ContentPasteIcon />}>Copy to clipboard</Button>
</Stack>
</Box>
)
);
}

View File

@@ -1,29 +1,18 @@
import {RouteObject} from "react-router-dom";
import {Navigate} from "react-router-dom";
import {ImagesConfig} from "../pages/images/ImagesConfig";
import {lazy} from "react";
import {StringConfig} from "../pages/string/StringConfig";
import { RouteObject } from 'react-router-dom';
import { Navigate } from 'react-router-dom';
import { lazy } from 'react';
const Home = lazy(() => import("../pages/home"));
const Home = lazy(() => import('../pages/home'));
const routes: RouteObject[] = [
{
path: "/",
element: <Home/>,
path: '/',
element: <Home />
},
{
path: "images",
children: ImagesConfig
},
{
path: "string",
children: StringConfig
},
{
path: "*",
element: <Navigate to="404"/>,
},
path: '*',
element: <Navigate to="404" />
}
];
export default routes;

View File

@@ -1,5 +1,5 @@
import {useCallback, useEffect, useRef} from "react";
import _ from "lodash";
import { useCallback, useEffect, useRef } from 'react';
import _ from 'lodash';
/**
* Debounce hook.
@@ -9,7 +9,7 @@ import _ from "lodash";
*/
function useDebounce<T extends (...args: never[]) => void>(
callback: T,
delay: number,
delay: number
): T {
const callbackRef = useRef<T>(callback);
@@ -22,7 +22,7 @@ function useDebounce<T extends (...args: never[]) => void>(
_.debounce((...args: never[]) => {
callbackRef.current(...args);
}, delay),
[delay],
[delay]
);
useEffect(() => {

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useEffect, useRef } from 'react';
/**
* The usePrevious function is a custom hook that returns the previous value of a variable.

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useEffect, useRef } from 'react';
/**
* The useTimeout function is a custom hook that sets a timeout for a given callback function.
@@ -15,7 +15,7 @@ function useTimeout(callback: () => void, delay: number) {
useEffect(() => {
let timer: NodeJS.Timeout | undefined;
if (delay !== null && callback && typeof callback === "function") {
if (delay !== null && callback && typeof callback === 'function') {
timer = setTimeout(callbackRef.current, delay);
}

View File

@@ -1,4 +1,4 @@
import { DependencyList, EffectCallback, useEffect, useRef } from "react";
import { DependencyList, EffectCallback, useEffect, useRef } from 'react';
/**
* The useUpdateEffect function is a custom hook that behaves like useEffect, but only runs on updates and not on initial mount.

View File

@@ -1,8 +1,8 @@
import { createRoot } from 'react-dom/client'
import 'tailwindcss/tailwind.css'
import App from 'components/App'
import { createRoot } from 'react-dom/client';
import 'tailwindcss/tailwind.css';
import App from 'components/App';
const container = document.getElementById('root') as HTMLDivElement
const root = createRoot(container)
const container = document.getElementById('root') as HTMLDivElement;
const root = createRoot(container);
root.render(<App />)
root.render(<App />);

View File

@@ -1,62 +1,83 @@
import {Box, Icon, Input, Stack, TextField} from "@mui/material";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import { Box, Stack, TextField } from '@mui/material';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import SearchIcon from '@mui/icons-material/Search';
import {useNavigate} from "react-router-dom";
import { useNavigate } from 'react-router-dom';
const exampleTools: { label: string; url: string }[] = [{
label: 'Create a transparent image',
url: ''
},
{label: 'Convert text to morse code', url: ''},
{label: 'Change GIF speed', url: ''},
{label: 'Pick a random item', url: ''},
{label: 'Find and replace text', url: ''},
{label: 'Convert emoji to image', url: ''},
{label: 'Split a string', url: '/string/split'},
{label: 'Calculate number sum', url: ''},
{label: 'Pixelate an image', url: ''},
]
const exampleTools: { label: string; url: string }[] = [
{
label: 'Create a transparent image',
url: ''
},
{ label: 'Convert text to morse code', url: '' },
{ label: 'Change GIF speed', url: '' },
{ label: 'Pick a random item', url: '' },
{ label: 'Find and replace text', url: '' },
{ label: 'Convert emoji to image', url: '' },
{ label: 'Split a string', url: '/string/split' },
{ label: 'Calculate number sum', url: '' },
{ label: 'Pixelate an image', url: '' }
];
export default function Home() {
const navigate = useNavigate()
const navigate = useNavigate();
return (<Box padding={5} display={'flex'} flexDirection={'column'} alignItems={'center'} justifyContent={'center'}
width={'100%'}>
<Box width={"60%"}>
<Stack mb={1} direction={'row'} spacing={1}> <Typography fontSize={30}>Transform Your Workflow
with </Typography><Typography
fontSize={30}
color={'primary'}>Omni
Tools</Typography></Stack>
<Typography fontSize={20} mb={2}>
Boost your productivity with Omni Tools, the ultimate toolkit for getting things done quickly! Access thousands
of
user-friendly utilities for editing images, text, lists, and data, all directly from your browser.
</Typography>
return (
<Box
padding={5}
display={'flex'}
flexDirection={'column'}
alignItems={'center'}
justifyContent={'center'}
width={'100%'}
>
<Box width={'60%'}>
<Stack mb={1} direction={'row'} spacing={1}>
{' '}
<Typography fontSize={30}>Transform Your Workflow with </Typography>
<Typography fontSize={30} color={'primary'}>
Omni Tools
</Typography>
</Stack>
<Typography fontSize={20} mb={2}>
Boost your productivity with Omni Tools, the ultimate toolkit for
getting things done quickly! Access thousands of user-friendly
utilities for editing images, text, lists, and data, all directly from
your browser.
</Typography>
<TextField fullWidth placeholder={'Search all tools'} sx={{borderRadius: 2}} InputProps={{
endAdornment: (
<SearchIcon/>
),
}}/>
<Grid container spacing={1} mt={2}>
{exampleTools.map((tool) => (
<Grid
onClick={() => navigate(tool.url)}
item
xs={4}
key={tool.label}
display="flex"
flexDirection="row"
justifyContent="center"
alignItems="center"
padding={2}
sx={{borderWidth: 1, borderRadius: 3, borderColor: 'grey', borderStyle: 'solid', cursor: 'pointer'}}
>
<Typography>{tool.label}</Typography>
</Grid>
))}
</Grid>
<TextField
fullWidth
placeholder={'Search all tools'}
sx={{ borderRadius: 2 }}
InputProps={{
endAdornment: <SearchIcon />
}}
/>
<Grid container spacing={1} mt={2}>
{exampleTools.map((tool) => (
<Grid
onClick={() => navigate(tool.url)}
item
xs={4}
key={tool.label}
display="flex"
flexDirection="row"
justifyContent="center"
alignItems="center"
padding={2}
sx={{
borderWidth: 1,
borderRadius: 3,
borderColor: 'grey',
borderStyle: 'solid',
cursor: 'pointer'
}}
>
<Typography>{tool.label}</Typography>
</Grid>
))}
</Grid>
</Box>
</Box>
</Box>)
);
}

View File

@@ -1,10 +0,0 @@
import {RouteObject} from "react-router-dom";
import {lazy} from "react";
import {PngConfig} from "./png/PngConfig";
const PngHome = lazy(() => import("./index"));
export const ImagesConfig: RouteObject[] = [
{path: '', element: <PngHome/>},
{path: 'png', children: PngConfig},
]

View File

@@ -0,0 +1,3 @@
import { pngTools } from './png/pngTools';
export const imageTools = [...pngTools];

View File

@@ -1,5 +1,5 @@
import {Box} from "@mui/material";
import { Box } from '@mui/material';
export default function ImageHome() {
return (<Box></Box>)
return <Box></Box>;
}

View File

@@ -1,10 +0,0 @@
import {RouteObject} from "react-router-dom";
import {lazy} from "react";
const ChangeColorsInPng = lazy(() => import("./change-colors-in-png"));
const PngHome = lazy(() => import("./"));
export const PngConfig: RouteObject[] = [
{path: '', element: <PngHome/>},
{path: 'change-colors-in-png', element: <ChangeColorsInPng/>}
]

View File

@@ -1,4 +1,4 @@
import { Box } from "@mui/material";
import { Box } from '@mui/material';
export default function ChangeColorsInPng() {
return <Box></Box>;

View File

@@ -0,0 +1,11 @@
import { defineTool } from '../../../../tools/defineTool';
import { lazy } from 'react';
export const tool = defineTool('png', {
path: 'change-colors',
name: 'Change colors in PNG',
description:
"World's simplest browser-based utility for splitting text. Load your text in the input form on the left and you'll automatically get pieces of this text on the right. Powerful, free, and fast. Load text get chunks.",
keywords: ['png', 'split'],
component: lazy(() => import('./index'))
});

View File

@@ -1,5 +1,5 @@
import {Box} from "@mui/material";
import { Box } from '@mui/material';
export default function PngHome() {
return (<Box></Box>)
return <Box></Box>;
}

View File

@@ -0,0 +1,3 @@
import { tool as changeColorsInPng } from './change-colors-in-png/meta';
export const pngTools = [changeColorsInPng];

View File

@@ -1,10 +0,0 @@
import {RouteObject} from "react-router-dom";
import {lazy} from "react";
const StringHome = lazy(() => import("./index"));
const StringSplit = lazy(() => import("./split"));
export const StringConfig: RouteObject[] = [
{path: '', element: <StringHome/>},
{path: 'split', element: <StringSplit/>},
]

View File

@@ -1,5 +1,5 @@
import {Box} from "@mui/material";
import { Box } from '@mui/material';
export default function StringHome() {
return (<Box></Box>)
return <Box></Box>;
}

View File

@@ -186,12 +186,7 @@ export default function SplitText() {
});
return (
<ToolLayout
title={'Text Splitter'}
description={
"World's simplest browser-based utility for splitting text. Load your text in the input form on the left and you'll automatically get pieces of this text on the right. Powerful, free, and fast. Load text get chunks."
}
>
<Box>
<Grid container spacing={2}>
<Grid item xs={6}>
<ToolTextInput value={input} onChange={setInput} />
@@ -242,6 +237,6 @@ export default function SplitText() {
)}
</Formik>
</ToolOptions>
</ToolLayout>
</Box>
);
}

View File

@@ -0,0 +1,11 @@
import { defineTool } from '../../../tools/defineTool';
import { lazy } from 'react';
export const tool = defineTool('string', {
path: 'split',
name: 'Text splitter',
description:
"World's simplest browser-based utility for splitting text. Load your text in the input form on the left and you'll automatically get pieces of this text on the right. Powerful, free, and fast. Load text get chunks.",
keywords: ['text', 'split'],
component: lazy(() => import('./index'))
});

View File

@@ -0,0 +1,3 @@
import { tool as stringSplit } from './split/meta';
export const stringTools = [stringSplit];

39
src/tools/defineTool.tsx Normal file
View File

@@ -0,0 +1,39 @@
import ToolLayout from '../components/ToolLayout';
import React, { LazyExoticComponent, JSXElementConstructor } from 'react';
interface ToolOptions {
path: string;
component: LazyExoticComponent<JSXElementConstructor<NonNullable<unknown>>>;
keywords: string[];
name: string;
description: string;
}
interface DefinedTool {
path: string;
name: string;
description: string;
keywords: string[];
component: () => JSX.Element;
}
export const defineTool = (
basePath: string,
options: ToolOptions
): DefinedTool => {
const { path, name, description, keywords, component } = options;
const Component = component;
return {
path: `${basePath}/${path}`,
name,
description,
keywords,
component: () => {
return (
<ToolLayout title={name} description={description}>
<Component />
</ToolLayout>
);
}
};
};

4
src/tools/index.ts Normal file
View File

@@ -0,0 +1,4 @@
import { stringTools } from '../pages/string/stringTools';
import { imageTools } from '../pages/images/imageTools';
export const tools = [...stringTools, ...imageTools];

View File

@@ -1,3 +1,3 @@
export function classNames(...classes: unknown[]): string {
return classes.filter(Boolean).join(' ')
return classes.filter(Boolean).join(' ');
}

View File

@@ -6,4 +6,4 @@ export default {
extend: {}
},
plugins: []
}
};