diff --git a/.eslintrc b/.eslintrc
index 6a44f8c..ef1ea0f 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -15,7 +15,7 @@
"plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
- "plugin:prettier/recommended",
+ // "plugin:prettier/recommended",
"plugin:tailwindcss/recommended"
],
"parser": "@typescript-eslint/parser",
@@ -26,7 +26,12 @@
"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",
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..14ad7b1
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..a604522
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/omni-tools.iml b/.idea/omni-tools.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/.idea/omni-tools.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
index 0e5c1db..e9c0f50 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,5 +1,4 @@
{
"trailingComma": "none",
- "semi": false,
"singleQuote": true
}
diff --git a/package-lock.json b/package-lock.json
index c5761e1..fee9f1e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,10 +13,12 @@
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@types/lodash": "^4.17.5",
+ "formik": "^2.4.6",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-router-dom": "^6.23.1"
+ "react-router-dom": "^6.23.1",
+ "yup": "^1.4.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.4.5",
@@ -1972,6 +1974,15 @@
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
+ "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -3222,6 +3233,14 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
+ "node_modules/deepmerge": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
+ "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -4113,6 +4132,30 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/formik": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz",
+ "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://opencollective.com/formik"
+ }
+ ],
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "deepmerge": "^2.1.1",
+ "hoist-non-react-statics": "^3.3.0",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
+ "react-fast-compare": "^2.0.1",
+ "tiny-warning": "^1.0.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -5158,6 +5201,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -6005,6 +6053,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/property-expr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -6057,6 +6110,11 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-fast-compare": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
+ "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -6913,6 +6971,16 @@
"node": ">=0.8"
}
},
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
+ },
+ "node_modules/tiny-warning": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+ },
"node_modules/tinybench": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz",
@@ -6957,6 +7025,11 @@
"node": ">=8.0"
}
},
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
+ },
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
@@ -7007,8 +7080,7 @@
"node_modules/tslib": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
- "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
- "dev": true
+ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -7634,6 +7706,28 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/yup": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz",
+ "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==",
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
+ },
+ "node_modules/yup/node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
}
}
}
diff --git a/package.json b/package.json
index d5bbb0e..e6a8d16 100644
--- a/package.json
+++ b/package.json
@@ -27,10 +27,12 @@
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@types/lodash": "^4.17.5",
+ "formik": "^2.4.6",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-router-dom": "^6.23.1"
+ "react-router-dom": "^6.23.1",
+ "yup": "^1.4.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.4.5",
diff --git a/src/components/App.tsx b/src/components/App.tsx
index e8b24c4..11f665a 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,23 +1,22 @@
-import {BrowserRouter, useRoutes} from "react-router-dom";
-import routesConfig from "../config/routesConfig";
-import Navbar from "./Navbar";
-import {Suspense} from "react";
-import Loading from "./Loading";
-import {ThemeProvider} from "@mui/material";
-import theme from "../config/muiConfig";
+import { BrowserRouter, useRoutes } from 'react-router-dom'
+import routesConfig from '../config/routesConfig'
+import Navbar from './Navbar'
+import { Suspense } from 'react'
+import Loading from './Loading'
+import { ThemeProvider } from '@mui/material'
+import theme from '../config/muiConfig'
const AppRoutes = () => {
- return useRoutes(routesConfig);
-};
+ return useRoutes(routesConfig)
+}
function App() {
-
return (
-
- }>
-
+
+ }>
+
diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx
index f8b36b8..114b105 100644
--- a/src/components/Loading.tsx
+++ b/src/components/Loading.tsx
@@ -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,12 +12,12 @@ 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 (
- Chargement
+ Loading
div": {
- backgroundColor: "palette.secondary.main",
- },
+ '& > div': {
+ backgroundColor: 'palette.secondary.main'
+ }
}}
>
-
-
-
+
+
+
- );
+ )
}
-export default FuseLoading;
+export default FuseLoading
diff --git a/src/components/input/ToolTextInput.tsx b/src/components/input/ToolTextInput.tsx
new file mode 100644
index 0000000..7920e61
--- /dev/null
+++ b/src/components/input/ToolTextInput.tsx
@@ -0,0 +1,31 @@
+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' }: {
+ title?: string;
+ value: string
+ onChange: (value: string) => void
+}) {
+ return (
+
+
+ {title}
+
+ onChange(event.target.value)}
+ fullWidth
+ multiline
+ rows={10}
+ />
+
+ }>Import from file
+ }>Copy to clipboard
+
+
+ )
+}
diff --git a/src/components/result/ToolTextResult.tsx b/src/components/result/ToolTextResult.tsx
new file mode 100644
index 0000000..916b132
--- /dev/null
+++ b/src/components/result/ToolTextResult.tsx
@@ -0,0 +1,21 @@
+import Typography from '@mui/material/Typography'
+import { Box, Stack, TextField } from '@mui/material'
+import Button from '@mui/material/Button'
+import DownloadIcon from '@mui/icons-material/Download'
+import ContentPasteIcon from '@mui/icons-material/ContentPaste'
+import React from 'react'
+
+export default function ToolTextResult({ title = 'Result', value }: { title?: string; value: string }) {
+ return (
+
+
+ {title}
+
+
+
+ }>Save as
+ }>Copy to clipboard
+
+
+ )
+}
diff --git a/src/config/muiConfig.ts b/src/config/muiConfig.ts
index 53308fc..0aeb41b 100644
--- a/src/config/muiConfig.ts
+++ b/src/config/muiConfig.ts
@@ -1,11 +1,12 @@
-import {createTheme} from "@mui/material";
+import { createTheme } from '@mui/material'
const theme = createTheme({
typography: {
button: {
textTransform: 'none'
}
- }
-});
+ },
+ palette: { background: { default: '#ebf5ff' } }
+})
-export default theme;
+export default theme
diff --git a/src/pages/images/png/change-colors-in-png/index.tsx b/src/pages/images/png/change-colors-in-png/index.tsx
index a5286a7..1229f9f 100644
--- a/src/pages/images/png/change-colors-in-png/index.tsx
+++ b/src/pages/images/png/change-colors-in-png/index.tsx
@@ -1,5 +1,5 @@
import { Box } from "@mui/material";
-export default function ChangeColorsInPng(){
- return()
+export default function ChangeColorsInPng() {
+ return ;
}
diff --git a/src/pages/string/split/index.tsx b/src/pages/string/split/index.tsx
index 4b590a2..87818ed 100644
--- a/src/pages/string/split/index.tsx
+++ b/src/pages/string/split/index.tsx
@@ -1,45 +1,169 @@
-import ToolHeader from "../../../components/ToolHeader";
-import ToolLayout from "../../../components/ToolLayout";
-import {Box, Stack, TextField} from "@mui/material";
-import Grid from "@mui/material/Grid";
-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 DownloadIcon from '@mui/icons-material/Download';
-import React, {useEffect, useState} from "react";
+import ToolHeader from '../../../components/ToolHeader'
+import ToolLayout from '../../../components/ToolLayout'
+import { Box, Radio, Stack, TextField, useTheme } from '@mui/material'
+import Grid from '@mui/material/Grid'
+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 DownloadIcon from '@mui/icons-material/Download'
+import React, { useEffect, useRef, useState } from 'react'
+import ToolTextInput from '../../../components/input/ToolTextInput'
+import ToolTextResult from '../../../components/result/ToolTextResult'
+import SettingsIcon from '@mui/icons-material/Settings'
+import { Field, Formik, FormikProps } from 'formik'
+import * as Yup from 'yup'
+type SplitOperatorType = 'symbol' | 'regex' | 'length' | 'chunks';
+const initialValues = {
+ splitSeparatorType: 'symbol',
+ splitSeparator: ' '
+}
+const initialSplitOperators: {
+ title: string;
+ description: string;
+ defaultValue: string;
+ type: SplitOperatorType
+}[] = [{
+ title: 'Use a Symbol for Splitting', description: 'Character that will be used to\n' +
+ 'break text into parts.\n' +
+ '(Space by default.)',
+ defaultValue: ' ',
+ type: 'symbol'
+},
+ {
+ title: 'Use a Regex for Splitting',
+ defaultValue: '/\\s+/',
+ type: 'regex',
+ description: 'Regular expression that will be\n' +
+ 'used to break text into parts.\n' +
+ '(Multiple spaces by default.)'
+ },
+ {
+ title: 'Use Length for Splitting', description: 'Number of symbols that will be\n' +
+ 'put in each output chunk.',
+ defaultValue: '16',
+ type: 'length'
+ },
+ {
+ title: 'Use a Number of Chunks', description: 'Number of chunks of equal\n' +
+ 'length in the output.',
+ defaultValue: '4',
+ type: 'chunks'
+ }]
+
+const CustomRadioButton = ({
+ fieldName,
+ type,
+ title,
+ setFieldValue,
+ value,
+ description,
+ onTextChange
+ }: {
+ fieldName: string;
+ title: string;
+ type: SplitOperatorType;
+ setFieldValue: (fieldName: string, val: string) => void;
+ value: string;
+ description: string;
+ onTextChange: (type: SplitOperatorType, value: string) => void;
+}) => {
+ const onChange = () => setFieldValue(fieldName, type)
+ return (
+
+
+ {title}
+
+ onTextChange(type, event.target.value)} />
+ {description}
+
+ )
+}
export default function SplitText() {
- const [input, setInput] = useState('');
+ const [input, setInput] = useState('')
const [result, setResult] = useState('')
+ const formRef = useRef>()
+ const theme = useTheme()
+ const [splitOperators, setSplitOperators] = useState<{
+ title: string;
+ description: string;
+ defaultValue: string;
+ type: SplitOperatorType;
+ value: string
+ }[]>(initialSplitOperators.map(operator => ({ ...operator, value: operator.defaultValue })))
useEffect(() => {
setResult(input.split(' ').join('\n'))
- }, [input]);
+ }, [input])
+
+ const validationSchema = Yup.object({
+ splitSeparator: Yup.string().required('The separator is required')
+ })
+
+ const onSplitOperatorTextChange = (type: SplitOperatorType, value: string) => {
+ const splitOperatorsClone = [...splitOperators].map(splitOperator => {
+ if (splitOperator.type === type) {
+ splitOperator.value = value
+ }
+ return splitOperator
+ })
+ setSplitOperators(splitOperatorsClone)
+ }
return (
-
+
- Input text
- setInput(event.target.value)} fullWidth multiline rows={10}/>
-
-
-
-
+
- Text pieces
-
-
-
-
-
+
-
-
+
+
+
+ Tool options
+
+ {
+ }}
+ >
+ {({ setFieldValue }) => (
+
+
+ Split separator options
+ {splitOperators.map(({ title, description, type, value }) => )}
+
+
+
+ )}
+
- )
+
+ )
}