mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-15 12:09:30 +02:00
feat: string to morse
This commit is contained in:
110
.idea/workspace.xml
generated
110
.idea/workspace.xml
generated
@@ -4,11 +4,20 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="chore: ResultFooter">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: change color in png finished">
|
||||
<change afterPath="$PROJECT_DIR$/src/components/options/ToolOptionGroups.tsx" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/string/to-morse/index.tsx" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/string/to-morse/meta.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/string/to-morse/service.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/string/to-morse/to-morse.service.test.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" 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/options/ColorSelector.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/options/ColorSelector.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/image/png/change-colors-in-png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/image/png/change-colors-in-png/index.tsx" 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$/scripts/create-tool.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/create-tool.mjs" 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/string/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/string/join/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/join/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" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -37,37 +46,38 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"Vitest.mergeText.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
|
||||
"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/assets",
|
||||
"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",
|
||||
"npm.script:create:tool.executor": "Run",
|
||||
"npm.test.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 name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"Vitest.compute function.executor": "Run",
|
||||
"Vitest.mergeText.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
|
||||
"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/assets",
|
||||
"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",
|
||||
"npm.script:create:tool.executor": "Run",
|
||||
"npm.test.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>
|
||||
@@ -91,7 +101,20 @@
|
||||
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\tools" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="npm.dev">
|
||||
<component name="RunManager" selected="Vitest.compute function">
|
||||
<configuration name="compute function" type="JavaScriptTestRunnerVitest" temporary="true" nameIsGenerated="true">
|
||||
<node-interpreter value="project" />
|
||||
<vitest-package value="$PROJECT_DIR$/node_modules/vitest" />
|
||||
<working-dir value="$PROJECT_DIR$" />
|
||||
<vitest-options value="--run" />
|
||||
<envs />
|
||||
<scope-kind value="SUITE" />
|
||||
<test-file value="$PROJECT_DIR$/src/pages/string/to-morse/to-morse.service.test.ts" />
|
||||
<test-names>
|
||||
<test-name value="compute function" />
|
||||
</test-names>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="dev" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
@@ -134,6 +157,7 @@
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Vitest.compute function" />
|
||||
<item itemvalue="npm.dev" />
|
||||
<item itemvalue="npm.test" />
|
||||
<item itemvalue="npm.script:create:tool" />
|
||||
@@ -163,7 +187,7 @@
|
||||
<workItem from="1719166718305" duration="1783000" />
|
||||
<workItem from="1719168519203" duration="17675000" />
|
||||
<workItem from="1719197816332" duration="1453000" />
|
||||
<workItem from="1719273044735" duration="2109000" />
|
||||
<workItem from="1719273044735" duration="4589000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="feat: use vite and ts">
|
||||
<option name="closed" value="true" />
|
||||
@@ -549,7 +573,15 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1719274243788</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="49" />
|
||||
<task id="LOCAL-00049" summary="feat: change color in png finished">
|
||||
<option name="closed" value="true" />
|
||||
<created>1719275214988</created>
|
||||
<option name="number" value="00049" />
|
||||
<option name="presentableId" value="LOCAL-00049" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1719275214988</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="50" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -570,7 +602,6 @@
|
||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
||||
<option name="CHECK_NEW_TODO" value="false" />
|
||||
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
|
||||
<MESSAGE value="test: init" />
|
||||
<MESSAGE value="chore: remove prebuild" />
|
||||
<MESSAGE value="chore: idea config" />
|
||||
<MESSAGE value="feat: react helmet" />
|
||||
@@ -595,7 +626,8 @@
|
||||
<MESSAGE value="feat: change colors in png init" />
|
||||
<MESSAGE value="feat: change colors in png" />
|
||||
<MESSAGE value="chore: ResultFooter" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="chore: ResultFooter" />
|
||||
<MESSAGE value="feat: change color in png finished" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat: change color in png finished" />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@@ -13,9 +13,11 @@
|
||||
"@mui/icons-material": "^5.15.20",
|
||||
"@mui/material": "^5.15.20",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/morsee": "^1.0.2",
|
||||
"color": "^4.2.3",
|
||||
"formik": "^2.4.6",
|
||||
"lodash": "^4.17.21",
|
||||
"morsee": "^1.0.9",
|
||||
"notistack": "^3.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@@ -2476,6 +2478,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz",
|
||||
"integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw=="
|
||||
},
|
||||
"node_modules/@types/morsee": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/morsee/-/morsee-1.0.2.tgz",
|
||||
"integrity": "sha512-WANv1kCyQtmGZTiov9FzFdt1X4wRtXYZA6B4YR3CghKgx4ychU7d1gkOx7oD+ddVGI+SWmWOPccco7pAc6wXeA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz",
|
||||
@@ -6194,6 +6201,11 @@
|
||||
"ufo": "^1.5.3"
|
||||
}
|
||||
},
|
||||
"node_modules/morsee": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/morsee/-/morsee-1.0.9.tgz",
|
||||
"integrity": "sha512-8X8jKVUmZBHKpET9Ap6FPiwlAAASvv60M1K25/YwCU7veuj5MfYgaWX3oEPHtMGgC44IIkIKzyD73fduEKB/9g=="
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||
|
@@ -29,9 +29,11 @@
|
||||
"@mui/icons-material": "^5.15.20",
|
||||
"@mui/material": "^5.15.20",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/morsee": "^1.0.2",
|
||||
"color": "^4.2.3",
|
||||
"formik": "^2.4.6",
|
||||
"lodash": "^4.17.21",
|
||||
"morsee": "^1.0.9",
|
||||
"notistack": "^3.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
@@ -45,7 +45,7 @@ const toolNameCamelCase = toolName.replace(/-./g, (x) => x[1].toUpperCase())
|
||||
const toolNameTitleCase =
|
||||
toolName[0].toUpperCase() + toolName.slice(1).replace(/-/g, ' ')
|
||||
const toolDir = join(toolsDir, toolName)
|
||||
|
||||
const type = folder.split(sep)[folder.split(sep).length - 1]
|
||||
await createFolderStructure(toolDir, folder.split(sep).length)
|
||||
console.log(`Directory created: ${toolDir}`)
|
||||
|
||||
@@ -78,7 +78,7 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('${folder.split(sep)[folder.split(sep).length - 1]}', {
|
||||
export const tool = defineTool('${type}', {
|
||||
name: '${toolNameTitleCase}',
|
||||
path: '${toolName}',
|
||||
// image,
|
||||
@@ -132,7 +132,7 @@ const indexContent = await readFile(toolsIndex, { encoding: 'utf-8' }).then(
|
||||
indexContent.splice(
|
||||
0,
|
||||
0,
|
||||
`import { tool as ${toolNameCamelCase} } from './${toolName}/meta';`
|
||||
`import { tool as ${type}${capitalizeFirstLetter(toolNameCamelCase)} } from './${toolName}/meta';`
|
||||
)
|
||||
writeFile(toolsIndex, indexContent.join('\n'))
|
||||
console.log(`Added import in: ${toolsIndex}`)
|
||||
|
20
src/components/options/ToolOptionGroups.tsx
Normal file
20
src/components/options/ToolOptionGroups.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { Box, Stack } from '@mui/material';
|
||||
|
||||
export default function ToolOptionGroups({
|
||||
groups
|
||||
}: {
|
||||
groups: { title: string; component: ReactNode }[];
|
||||
}) {
|
||||
return (
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
{groups.map((group) => (
|
||||
<Box key={group.title}>
|
||||
<Typography fontSize={22}>{group.title}</Typography>
|
||||
{group.component}
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
}
|
@@ -12,7 +12,7 @@ import SearchIcon from '@mui/icons-material/Search';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { filterTools, getToolsByCategory, tools } from '../../tools';
|
||||
import { useState } from 'react';
|
||||
import { DefinedTool } from '../../tools/defineTool';
|
||||
import { DefinedTool } from '@tools/defineTool';
|
||||
import Button from '@mui/material/Button';
|
||||
|
||||
const exampleTools: { label: string; url: string }[] = [
|
||||
@@ -20,7 +20,7 @@ const exampleTools: { label: string; url: string }[] = [
|
||||
label: 'Create a transparent image',
|
||||
url: ''
|
||||
},
|
||||
{ label: 'Convert text to morse code', url: '' },
|
||||
{ label: 'Convert text to morse code', url: '/string/to-morse' },
|
||||
{ label: 'Change GIF speed', url: '' },
|
||||
{ label: 'Pick a random item', url: '' },
|
||||
{ label: 'Find and replace text', url: '' },
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { tool as stringToMorse } from './to-morse/meta';
|
||||
import { tool as stringSplit } from './split/meta';
|
||||
import { tool as stringJoin } from './join/meta';
|
||||
|
||||
export const stringTools = [stringSplit, stringJoin];
|
||||
export const stringTools = [stringSplit, stringJoin, stringToMorse];
|
||||
|
@@ -9,6 +9,7 @@ import { mergeText } from './service';
|
||||
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';
|
||||
import TextFieldWithDesc from '../../../components/options/TextFieldWithDesc';
|
||||
import CheckboxWithDesc from '../../../components/options/CheckboxWithDesc';
|
||||
import ToolOptionGroups from '../../../components/options/ToolOptionGroups';
|
||||
|
||||
const initialValues = {
|
||||
joinCharacter: '',
|
||||
@@ -90,31 +91,37 @@ export default function JoinText() {
|
||||
{({ setFieldValue, values }) => (
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<FormikListenerComponent input={input} />
|
||||
<Box>
|
||||
<Typography fontSize={22}>Text Merged Options</Typography>
|
||||
<TextFieldWithDesc
|
||||
placeholder={mergeOptions.placeholder}
|
||||
value={values['joinCharacter']}
|
||||
onChange={(value) =>
|
||||
setFieldValue(mergeOptions.accessor, value)
|
||||
<ToolOptionGroups
|
||||
groups={[
|
||||
{
|
||||
title: 'Text Merged Options',
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
placeholder={mergeOptions.placeholder}
|
||||
value={values['joinCharacter']}
|
||||
onChange={(value) =>
|
||||
setFieldValue(mergeOptions.accessor, value)
|
||||
}
|
||||
description={mergeOptions.description}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Blank Lines and Trailing Spaces',
|
||||
component: blankTrailingOptions.map((option) => (
|
||||
<CheckboxWithDesc
|
||||
key={option.accessor}
|
||||
title={option.title}
|
||||
checked={!!values[option.accessor]}
|
||||
onChange={(value) =>
|
||||
setFieldValue(option.accessor, value)
|
||||
}
|
||||
description={option.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
description={mergeOptions.description}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography fontSize={22}>
|
||||
Blank Lines and Trailing Spaces
|
||||
</Typography>
|
||||
{blankTrailingOptions.map((option) => (
|
||||
<CheckboxWithDesc
|
||||
key={option.accessor}
|
||||
title={option.title}
|
||||
checked={!!values[option.accessor]}
|
||||
onChange={(value) => setFieldValue(option.accessor, value)}
|
||||
description={option.description}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</Formik>
|
||||
|
@@ -1,16 +1,16 @@
|
||||
import { Box, Stack, TextField } from '@mui/material';
|
||||
import { Box, Stack } from '@mui/material';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import ToolTextInput from '../../../components/input/ToolTextInput';
|
||||
import ToolTextResult from '../../../components/result/ToolTextResult';
|
||||
import { Field, Formik, FormikProps, useFormikContext } from 'formik';
|
||||
import { Formik, useFormikContext } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import ToolOptions from '../../../components/options/ToolOptions';
|
||||
import { compute, SplitOperatorType } from './service';
|
||||
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';
|
||||
import RadioWithTextField from '../../../components/options/RadioWithTextField';
|
||||
import TextFieldWithDesc from '../../../components/options/TextFieldWithDesc';
|
||||
import ToolOptionGroups from '../../../components/options/ToolOptionGroups';
|
||||
|
||||
const initialValues = {
|
||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||
@@ -143,34 +143,44 @@ export default function SplitText() {
|
||||
{({ setFieldValue, values }) => (
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<FormikListenerComponent />
|
||||
<Box>
|
||||
<Typography fontSize={22}>Split separator options</Typography>
|
||||
{splitOperators.map(({ title, description, type }) => (
|
||||
<RadioWithTextField
|
||||
key={type}
|
||||
type={type}
|
||||
title={title}
|
||||
fieldName={'splitSeparatorType'}
|
||||
description={description}
|
||||
value={values[`${type}Value`]}
|
||||
onTypeChange={(type) =>
|
||||
setFieldValue('splitSeparatorType', type)
|
||||
}
|
||||
onTextChange={(val) => setFieldValue(`${type}Value`, val)}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography fontSize={22}>Output separator options</Typography>
|
||||
{outputOptions.map((option) => (
|
||||
<TextFieldWithDesc
|
||||
key={option.accessor}
|
||||
value={values[option.accessor]}
|
||||
onChange={(value) => setFieldValue(option.accessor, value)}
|
||||
description={option.description}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
<ToolOptionGroups
|
||||
groups={[
|
||||
{
|
||||
title: 'Split separator options',
|
||||
component: splitOperators.map(
|
||||
({ title, description, type }) => (
|
||||
<RadioWithTextField
|
||||
key={type}
|
||||
type={type}
|
||||
title={title}
|
||||
fieldName={'splitSeparatorType'}
|
||||
description={description}
|
||||
value={values[`${type}Value`]}
|
||||
onTypeChange={(type) =>
|
||||
setFieldValue('splitSeparatorType', type)
|
||||
}
|
||||
onTextChange={(val) =>
|
||||
setFieldValue(`${type}Value`, val)
|
||||
}
|
||||
/>
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Output separator options',
|
||||
component: outputOptions.map((option) => (
|
||||
<TextFieldWithDesc
|
||||
key={option.accessor}
|
||||
value={values[option.accessor]}
|
||||
onChange={(value) =>
|
||||
setFieldValue(option.accessor, value)
|
||||
}
|
||||
description={option.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</Formik>
|
||||
|
98
src/pages/string/to-morse/index.tsx
Normal file
98
src/pages/string/to-morse/index.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import { Box, Stack } from '@mui/material';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import ToolTextInput from '../../../components/input/ToolTextInput';
|
||||
import ToolTextResult from '../../../components/result/ToolTextResult';
|
||||
import { Formik, useFormikContext } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import ToolOptions from '../../../components/options/ToolOptions';
|
||||
import { compute } from './service';
|
||||
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';
|
||||
import TextFieldWithDesc from '../../../components/options/TextFieldWithDesc';
|
||||
import ToolOptionGroups from '../../../components/options/ToolOptionGroups';
|
||||
|
||||
const initialValues = {
|
||||
dotSymbol: '.',
|
||||
dashSymbol: '-'
|
||||
};
|
||||
|
||||
export default function ToMorse() {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
// const formRef = useRef<FormikProps<typeof initialValues>>(null);
|
||||
const { showSnackBar } = useContext(CustomSnackBarContext);
|
||||
|
||||
const FormikListenerComponent = () => {
|
||||
const { values } = useFormikContext<typeof initialValues>();
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const { dotSymbol, dashSymbol } = values;
|
||||
|
||||
setResult(compute(input, dotSymbol, dashSymbol));
|
||||
} catch (exception: unknown) {
|
||||
if (exception instanceof Error)
|
||||
showSnackBar(exception.message, 'error');
|
||||
}
|
||||
}, [values, input]);
|
||||
|
||||
return null; // This component doesn't render anything
|
||||
};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<ToolTextInput value={input} onChange={setInput} />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<ToolTextResult title={'Morse code'} value={result} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<ToolOptions>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={() => {}}
|
||||
>
|
||||
{({ setFieldValue, values }) => (
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<FormikListenerComponent />
|
||||
<ToolOptionGroups
|
||||
groups={[
|
||||
{
|
||||
title: 'Short Signal',
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
description={
|
||||
'Symbol that will correspond to the dot in Morse code.'
|
||||
}
|
||||
value={values.dotSymbol}
|
||||
onChange={(val) => setFieldValue('dotSymbol', val)}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Long Signal',
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
description={
|
||||
'Symbol that will correspond to the dash in Morse code.'
|
||||
}
|
||||
value={values.dashSymbol}
|
||||
onChange={(val) => setFieldValue('dashSymbol', val)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</Formik>
|
||||
</ToolOptions>
|
||||
</Box>
|
||||
);
|
||||
}
|
12
src/pages/string/to-morse/meta.ts
Normal file
12
src/pages/string/to-morse/meta.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'String To morse',
|
||||
path: 'to-morse',
|
||||
// image,
|
||||
description: '',
|
||||
keywords: ['to', 'morse'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
9
src/pages/string/to-morse/service.ts
Normal file
9
src/pages/string/to-morse/service.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { encode } from 'morsee';
|
||||
|
||||
export const compute = (
|
||||
input: string,
|
||||
dotSymbol: string,
|
||||
dashSymbol: string
|
||||
): string => {
|
||||
return encode(input).replaceAll('.', dotSymbol).replaceAll('-', dashSymbol);
|
||||
};
|
50
src/pages/string/to-morse/to-morse.service.test.ts
Normal file
50
src/pages/string/to-morse/to-morse.service.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { compute } from './service';
|
||||
|
||||
describe('compute function', () => {
|
||||
it('should replace dots and dashes with specified symbols', () => {
|
||||
const input = 'test';
|
||||
const dotSymbol = '*';
|
||||
const dashSymbol = '#';
|
||||
const result = compute(input, dotSymbol, dashSymbol);
|
||||
const expected = '# * *** #';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should return an empty string for empty input', () => {
|
||||
const input = '';
|
||||
const dotSymbol = '*';
|
||||
const dashSymbol = '#';
|
||||
const result = compute(input, dotSymbol, dashSymbol);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
// Test case 3: Special characters handling
|
||||
it('should handle input with special characters', () => {
|
||||
const input = 'hello, world!';
|
||||
const dotSymbol = '*';
|
||||
const dashSymbol = '#';
|
||||
const result = compute(input, dotSymbol, dashSymbol);
|
||||
const expected =
|
||||
'**** * *#** *#** ### ##**## / *## ### *#* *#** #** #*#*##';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should work with different symbols for dots and dashes', () => {
|
||||
const input = 'morse';
|
||||
const dotSymbol = '!';
|
||||
const dashSymbol = '@';
|
||||
const result = compute(input, dotSymbol, dashSymbol);
|
||||
const expected = '@@ @@@ !@! !!! !';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('should handle numeric input correctly', () => {
|
||||
const input = '12345';
|
||||
const dotSymbol = '*';
|
||||
const dashSymbol = '#';
|
||||
const result = compute(input, dotSymbol, dashSymbol);
|
||||
const expected = '*#### **### ***## ****# *****'; // This depends on how "12345" is encoded in morse code
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user