mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-20 06:29:32 +02:00
feat: missing tools
This commit is contained in:
135
.idea/workspace.xml
generated
135
.idea/workspace.xml
generated
@@ -4,15 +4,18 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="refactor: validateJson">
|
||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="refactor: use ToolContent">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/options/CheckboxWithDesc.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/options/CheckboxWithDesc.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/duplicate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/duplicate/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/find-unique/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/find-unique/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/shuffle/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/shuffle/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/join/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/join/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/to-morse/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/to-morse/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/truncate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/truncate/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/unwrap/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/unwrap/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/wrap/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/wrap/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/quote/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/quote/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/rot13/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/rot13/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/rotate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/rotate/index.tsx" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -111,53 +114,53 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"Docker.Dockerfile build.executor": "Run",
|
||||
"Docker.Dockerfile.executor": "Run",
|
||||
"Playwright.JoinText Component.executor": "Run",
|
||||
"Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"Vitest.compute function (1).executor": "Run",
|
||||
"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",
|
||||
"Vitest.removeDuplicateLines function.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter.executor": "Run",
|
||||
"Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp.executor": "Run",
|
||||
"Vitest.replaceText function.executor": "Run",
|
||||
"git-widget-placeholder": "main",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/src/pages/tools/list/duplicate/index.tsx",
|
||||
"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.build.executor": "Run",
|
||||
"npm.dev.executor": "Run",
|
||||
"npm.lint.executor": "Run",
|
||||
"npm.prebuild.executor": "Run",
|
||||
"npm.script:create:tool.executor": "Run",
|
||||
"npm.test.executor": "Run",
|
||||
"npm.test:e2e.executor": "Run",
|
||||
"npm.test:e2e:run.executor": "Run",
|
||||
"prettierjs.PrettierConfiguration.Package": "C:\\Users\\Ibrahima\\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": "refactai_advanced_settings",
|
||||
"ts.external.directory.path": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"Docker.Dockerfile build.executor": "Run",
|
||||
"Docker.Dockerfile.executor": "Run",
|
||||
"Playwright.JoinText Component.executor": "Run",
|
||||
"Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"Vitest.compute function (1).executor": "Run",
|
||||
"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",
|
||||
"Vitest.removeDuplicateLines function.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter.executor": "Run",
|
||||
"Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp.executor": "Run",
|
||||
"Vitest.replaceText function.executor": "Run",
|
||||
"git-widget-placeholder": "main",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/src/pages/tools/list/duplicate/index.tsx",
|
||||
"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.build.executor": "Run",
|
||||
"npm.dev.executor": "Run",
|
||||
"npm.lint.executor": "Run",
|
||||
"npm.prebuild.executor": "Run",
|
||||
"npm.script:create:tool.executor": "Run",
|
||||
"npm.test.executor": "Run",
|
||||
"npm.test:e2e.executor": "Run",
|
||||
"npm.test:e2e:run.executor": "Run",
|
||||
"prettierjs.PrettierConfiguration.Package": "C:\\Users\\Ibrahima\\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": "refactai_advanced_settings",
|
||||
"ts.external.directory.path": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="ReactDesignerToolWindowState">
|
||||
<option name="myId2Visible">
|
||||
<map>
|
||||
@@ -183,7 +186,7 @@
|
||||
<recent name="C:\Users\HP\IdeaProjects\omni-tools\src\components\options" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp">
|
||||
<component name="RunManager" selected="npm.dev">
|
||||
<configuration name="replaceText function (regexp mode).should return the original text when passed an invalid regexp" type="JavaScriptTestRunnerVitest" temporary="true" nameIsGenerated="true">
|
||||
<node-interpreter value="project" />
|
||||
<vitest-package value="$PROJECT_DIR$/node_modules/vitest" />
|
||||
@@ -256,10 +259,10 @@
|
||||
</list>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="npm.dev" />
|
||||
<item itemvalue="Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp" />
|
||||
<item itemvalue="npm.test" />
|
||||
<item itemvalue="npm.test:e2e" />
|
||||
<item itemvalue="npm.dev" />
|
||||
<item itemvalue="Vitest.replaceText function" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
@@ -340,15 +343,7 @@
|
||||
<workItem from="1741475969294" duration="4215000" />
|
||||
<workItem from="1741494053121" duration="178000" />
|
||||
<workItem from="1741537936314" duration="1294000" />
|
||||
<workItem from="1741539602311" duration="1240000" />
|
||||
</task>
|
||||
<task id="LOCAL-00106" summary="fix: compress png">
|
||||
<option name="closed" value="true" />
|
||||
<created>1740322444616</created>
|
||||
<option name="number" value="00106" />
|
||||
<option name="presentableId" value="LOCAL-00106" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1740322444616</updated>
|
||||
<workItem from="1741539602311" duration="2441000" />
|
||||
</task>
|
||||
<task id="LOCAL-00107" summary="fix: docs">
|
||||
<option name="closed" value="true" />
|
||||
@@ -734,7 +729,15 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1741535390090</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="155" />
|
||||
<task id="LOCAL-00155" summary="refactor: use ToolContent">
|
||||
<option name="closed" value="true" />
|
||||
<created>1741540939154</created>
|
||||
<option name="number" value="00155" />
|
||||
<option name="presentableId" value="LOCAL-00155" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1741540939154</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="156" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -781,7 +784,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="chore: show tooloptions in example" />
|
||||
<MESSAGE value="refact: examples" />
|
||||
<MESSAGE value="fix: examples" />
|
||||
<MESSAGE value="feat: json pretty" />
|
||||
@@ -806,7 +808,8 @@
|
||||
<MESSAGE value="feat: crop png" />
|
||||
<MESSAGE value="chore: remove unnecessary files" />
|
||||
<MESSAGE value="refactor: validateJson" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="refactor: validateJson" />
|
||||
<MESSAGE value="refactor: use ToolContent" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="refactor: use ToolContent" />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
|
@@ -9,7 +9,7 @@ const CheckboxWithDesc = ({
|
||||
disabled
|
||||
}: {
|
||||
title: string;
|
||||
description: string;
|
||||
description?: string;
|
||||
checked: boolean;
|
||||
onChange: (value: boolean) => void;
|
||||
disabled?: boolean;
|
||||
@@ -30,9 +30,11 @@ const CheckboxWithDesc = ({
|
||||
}
|
||||
label={title}
|
||||
/>
|
||||
<Typography fontSize={12} mt={1}>
|
||||
{description}
|
||||
</Typography>
|
||||
{description && (
|
||||
<Typography fontSize={12} mt={1}>
|
||||
{description}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -1,12 +1,215 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { duplicateList, SplitOperatorType } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Duplicate() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
interface InitialValuesType {
|
||||
splitOperatorType: SplitOperatorType;
|
||||
splitSeparator: string;
|
||||
joinSeparator: string;
|
||||
concatenate: boolean;
|
||||
reverse: boolean;
|
||||
copy: string;
|
||||
}
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ' ',
|
||||
joinSeparator: ' ',
|
||||
concatenate: true,
|
||||
reverse: false,
|
||||
copy: '2'
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
splitSeparator: Yup.string().required('The separator is required'),
|
||||
joinSeparator: Yup.string().required('The join separator is required'),
|
||||
copy: Yup.number()
|
||||
.typeError('Number of copies must be a number')
|
||||
.min(0.1, 'Number of copies must be positive')
|
||||
.required('Number of copies is required')
|
||||
});
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Simple duplication',
|
||||
description: 'This example shows how to duplicate a list of words.',
|
||||
sampleText: 'Hello World',
|
||||
sampleResult: 'Hello World Hello World',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ' ',
|
||||
joinSeparator: ' ',
|
||||
concatenate: true,
|
||||
reverse: false,
|
||||
copy: '2'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Reverse duplication',
|
||||
description: 'This example shows how to duplicate a list in reverse order.',
|
||||
sampleText: 'Hello World',
|
||||
sampleResult: 'Hello World World Hello',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ' ',
|
||||
joinSeparator: ' ',
|
||||
concatenate: true,
|
||||
reverse: true,
|
||||
copy: '2'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Interweaving items',
|
||||
description:
|
||||
'This example shows how to interweave items instead of concatenating them.',
|
||||
sampleText: 'Hello World',
|
||||
sampleResult: 'Hello Hello World World',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ' ',
|
||||
joinSeparator: ' ',
|
||||
concatenate: false,
|
||||
reverse: false,
|
||||
copy: '2'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Fractional duplication',
|
||||
description:
|
||||
'This example shows how to duplicate a list with a fractional number of copies.',
|
||||
sampleText: 'apple banana cherry',
|
||||
sampleResult: 'apple banana cherry apple banana',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ' ',
|
||||
joinSeparator: ' ',
|
||||
concatenate: true,
|
||||
reverse: false,
|
||||
copy: '1.7'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Duplicate({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (optionsValues: InitialValuesType, input: string) => {
|
||||
if (input) {
|
||||
try {
|
||||
const copy = parseFloat(optionsValues.copy);
|
||||
setResult(
|
||||
duplicateList(
|
||||
optionsValues.splitOperatorType,
|
||||
optionsValues.splitSeparator,
|
||||
optionsValues.joinSeparator,
|
||||
input,
|
||||
optionsValues.concatenate,
|
||||
optionsValues.reverse,
|
||||
copy
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
setResult(`Error: ${error.message}`);
|
||||
} else {
|
||||
setResult('An unknown error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Split Options',
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'symbol')}
|
||||
checked={values.splitOperatorType === 'symbol'}
|
||||
title={'Split by Symbol'}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'regex')}
|
||||
checked={values.splitOperatorType === 'regex'}
|
||||
title={'Split by Regular Expression'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.splitSeparator}
|
||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||
description={'Separator to split the list'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.joinSeparator}
|
||||
onOwnChange={(val) => updateField('joinSeparator', val)}
|
||||
description={'Separator to join the duplicated list'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Duplication Options',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.copy}
|
||||
onOwnChange={(val) => updateField('copy', val)}
|
||||
description={'Number of copies (can be fractional)'}
|
||||
type="number"
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
title={'Concatenate'}
|
||||
checked={values.concatenate}
|
||||
onChange={(checked) => updateField('concatenate', checked)}
|
||||
description={
|
||||
'Concatenate copies (if unchecked, items will be interweaved)'
|
||||
}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
title={'Reverse'}
|
||||
checked={values.reverse}
|
||||
onChange={(checked) => updateField('reverse', checked)}
|
||||
description={'Reverse the duplicated items'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input List" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title="Duplicated List" value={result} />
|
||||
}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
validationSchema={validationSchema}
|
||||
toolInfo={{
|
||||
title: 'List Duplication',
|
||||
description:
|
||||
"This tool allows you to duplicate items in a list. You can specify the number of copies (including fractional values), control whether items are concatenated or interweaved, and even reverse the duplicated items. It's useful for creating repeated patterns, generating test data, or expanding lists with predictable content."
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -12,14 +12,14 @@ import { tool as listSort } from './sort/meta';
|
||||
|
||||
export const listTools = [
|
||||
listSort,
|
||||
// listUnwrap,
|
||||
listUnwrap,
|
||||
listReverse,
|
||||
listFindUnique,
|
||||
listFindMostPopular,
|
||||
listGroup,
|
||||
// listWrap,
|
||||
listWrap,
|
||||
listRotate,
|
||||
listShuffle
|
||||
// listTruncate,
|
||||
// listDuplicate
|
||||
listShuffle,
|
||||
listTruncate,
|
||||
listDuplicate
|
||||
];
|
||||
|
@@ -1,11 +1,189 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { SplitOperatorType, truncateList } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Truncate() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
interface InitialValuesType {
|
||||
splitOperatorType: SplitOperatorType;
|
||||
splitSeparator: string;
|
||||
joinSeparator: string;
|
||||
end: boolean;
|
||||
length: string;
|
||||
}
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ',',
|
||||
joinSeparator: ',',
|
||||
end: true,
|
||||
length: '3'
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
splitSeparator: Yup.string().required('The separator is required'),
|
||||
joinSeparator: Yup.string().required('The join separator is required'),
|
||||
length: Yup.number()
|
||||
.typeError('Length must be a number')
|
||||
.min(0, 'Length must be a positive number')
|
||||
.required('Length is required')
|
||||
});
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Keep first 3 items in a list',
|
||||
description:
|
||||
'This example shows how to keep only the first 3 items in a comma-separated list.',
|
||||
sampleText: 'apple, pineapple, lemon, orange, mango',
|
||||
sampleResult: 'apple,pineapple,lemon',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ', ',
|
||||
joinSeparator: ',',
|
||||
end: true,
|
||||
length: '3'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Keep last 2 items in a list',
|
||||
description:
|
||||
'This example shows how to keep only the last 2 items in a comma-separated list.',
|
||||
sampleText: 'apple, pineapple, lemon, orange, mango',
|
||||
sampleResult: 'orange,mango',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ', ',
|
||||
joinSeparator: ',',
|
||||
end: false,
|
||||
length: '2'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Truncate a list with custom separators',
|
||||
description:
|
||||
'This example shows how to truncate a list with custom separators.',
|
||||
sampleText: 'apple | pineapple | lemon | orange | mango',
|
||||
sampleResult: 'apple - pineapple - lemon',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ' | ',
|
||||
joinSeparator: ' - ',
|
||||
end: true,
|
||||
length: '3'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Truncate({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (optionsValues: InitialValuesType, input: string) => {
|
||||
if (input) {
|
||||
try {
|
||||
const length = parseInt(optionsValues.length, 10);
|
||||
setResult(
|
||||
truncateList(
|
||||
optionsValues.splitOperatorType,
|
||||
input,
|
||||
optionsValues.splitSeparator,
|
||||
optionsValues.joinSeparator,
|
||||
optionsValues.end,
|
||||
length
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
setResult(`Error: ${error.message}`);
|
||||
} else {
|
||||
setResult('An unknown error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Split Options',
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'symbol')}
|
||||
checked={values.splitOperatorType === 'symbol'}
|
||||
title={'Split by Symbol'}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'regex')}
|
||||
checked={values.splitOperatorType === 'regex'}
|
||||
title={'Split by Regular Expression'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.splitSeparator}
|
||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||
description={'Separator to split the list'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.joinSeparator}
|
||||
onOwnChange={(val) => updateField('joinSeparator', val)}
|
||||
description={'Separator to join the truncated list'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Truncation Options',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.length}
|
||||
onOwnChange={(val) => updateField('length', val)}
|
||||
description={'Number of items to keep'}
|
||||
type="number"
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('end', true)}
|
||||
checked={values.end}
|
||||
title={'Keep items from the beginning'}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('end', false)}
|
||||
checked={!values.end}
|
||||
title={'Keep items from the end'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input List" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="Truncated List" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
validationSchema={validationSchema}
|
||||
toolInfo={{
|
||||
title: 'List Truncation',
|
||||
description:
|
||||
"This tool allows you to truncate a list to a specific number of items. You can choose to keep items from the beginning or the end of the list, and specify custom separators for splitting and joining. It's useful for limiting the size of lists, creating previews, or extracting specific portions of data."
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -1,11 +1,212 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { SplitOperatorType, unwrapList } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Unwrap() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
interface InitialValuesType {
|
||||
splitOperatorType: SplitOperatorType;
|
||||
splitSeparator: string;
|
||||
joinSeparator: string;
|
||||
deleteEmptyItems: boolean;
|
||||
multiLevel: boolean;
|
||||
trimItems: boolean;
|
||||
left: string;
|
||||
right: string;
|
||||
}
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: '\n',
|
||||
joinSeparator: '\n',
|
||||
deleteEmptyItems: true,
|
||||
multiLevel: true,
|
||||
trimItems: true,
|
||||
left: '',
|
||||
right: ''
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
splitSeparator: Yup.string().required('The separator is required'),
|
||||
joinSeparator: Yup.string().required('The join separator is required')
|
||||
});
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Unwrap quotes from list items',
|
||||
description:
|
||||
'This example shows how to remove quotes from each item in a list.',
|
||||
sampleText: '"apple"\n"banana"\n"orange"',
|
||||
sampleResult: 'apple\nbanana\norange',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: '\n',
|
||||
joinSeparator: '\n',
|
||||
deleteEmptyItems: true,
|
||||
multiLevel: true,
|
||||
trimItems: true,
|
||||
left: '"',
|
||||
right: '"'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Unwrap multiple levels of characters',
|
||||
description:
|
||||
'This example shows how to remove multiple levels of the same character from each item.',
|
||||
sampleText: '###Hello###\n##World##\n#Test#',
|
||||
sampleResult: 'Hello\nWorld\nTest',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: '\n',
|
||||
joinSeparator: '\n',
|
||||
deleteEmptyItems: true,
|
||||
multiLevel: true,
|
||||
trimItems: true,
|
||||
left: '#',
|
||||
right: '#'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Unwrap and join with custom separator',
|
||||
description:
|
||||
'This example shows how to unwrap items and join them with a custom separator.',
|
||||
sampleText: '[item1]\n[item2]\n[item3]',
|
||||
sampleResult: 'item1, item2, item3',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: '\n',
|
||||
joinSeparator: ', ',
|
||||
deleteEmptyItems: true,
|
||||
multiLevel: false,
|
||||
trimItems: true,
|
||||
left: '[',
|
||||
right: ']'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Unwrap({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (optionsValues: InitialValuesType, input: string) => {
|
||||
if (input) {
|
||||
try {
|
||||
setResult(
|
||||
unwrapList(
|
||||
optionsValues.splitOperatorType,
|
||||
input,
|
||||
optionsValues.splitSeparator,
|
||||
optionsValues.joinSeparator,
|
||||
optionsValues.deleteEmptyItems,
|
||||
optionsValues.multiLevel,
|
||||
optionsValues.trimItems,
|
||||
optionsValues.left,
|
||||
optionsValues.right
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
setResult(`Error: ${error.message}`);
|
||||
} else {
|
||||
setResult('An unknown error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Split Options',
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'symbol')}
|
||||
checked={values.splitOperatorType === 'symbol'}
|
||||
title={'Split by Symbol'}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'regex')}
|
||||
checked={values.splitOperatorType === 'regex'}
|
||||
title={'Split by Regular Expression'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.splitSeparator}
|
||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||
description={'Separator to split the list'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.joinSeparator}
|
||||
onOwnChange={(val) => updateField('joinSeparator', val)}
|
||||
description={'Separator to join the unwrapped list'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Unwrap Options',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.left}
|
||||
onOwnChange={(val) => updateField('left', val)}
|
||||
description={'Characters to remove from the left side'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.right}
|
||||
onOwnChange={(val) => updateField('right', val)}
|
||||
description={'Characters to remove from the right side'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.multiLevel}
|
||||
onChange={(checked) => updateField('multiLevel', checked)}
|
||||
title={'Remove multiple levels of wrapping'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.trimItems}
|
||||
onChange={(checked) => updateField('trimItems', checked)}
|
||||
title={'Trim whitespace from items'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.deleteEmptyItems}
|
||||
onChange={(checked) => updateField('deleteEmptyItems', checked)}
|
||||
title={'Remove empty items'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input List" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="Unwrapped List" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
validationSchema={validationSchema}
|
||||
toolInfo={{
|
||||
title: 'List Unwrapping',
|
||||
description:
|
||||
"This tool allows you to remove wrapping characters from each item in a list. You can specify characters to remove from the left and right sides, handle multiple levels of wrapping, and control how the list is processed. It's useful for cleaning up data, removing quotes or brackets, and formatting lists."
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -1,11 +1,191 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { SplitOperatorType, wrapList } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Wrap() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
interface InitialValuesType {
|
||||
splitOperatorType: SplitOperatorType;
|
||||
splitSeparator: string;
|
||||
joinSeparator: string;
|
||||
deleteEmptyItems: boolean;
|
||||
left: string;
|
||||
right: string;
|
||||
}
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ',',
|
||||
joinSeparator: ',',
|
||||
deleteEmptyItems: true,
|
||||
left: '"',
|
||||
right: '"'
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
splitSeparator: Yup.string().required('The separator is required'),
|
||||
joinSeparator: Yup.string().required('The join separator is required')
|
||||
});
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Wrap list items with quotes',
|
||||
description:
|
||||
'This example shows how to wrap each item in a list with quotes.',
|
||||
sampleText: 'apple,banana,orange',
|
||||
sampleResult: '"apple","banana","orange"',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ',',
|
||||
joinSeparator: ',',
|
||||
deleteEmptyItems: true,
|
||||
left: '"',
|
||||
right: '"'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Wrap list items with brackets',
|
||||
description:
|
||||
'This example shows how to wrap each item in a list with brackets.',
|
||||
sampleText: 'item1,item2,item3',
|
||||
sampleResult: '[item1],[item2],[item3]',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ',',
|
||||
joinSeparator: ',',
|
||||
deleteEmptyItems: true,
|
||||
left: '[',
|
||||
right: ']'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Wrap list items with custom text',
|
||||
description:
|
||||
'This example shows how to wrap each item with different text on each side.',
|
||||
sampleText: 'apple,banana,orange',
|
||||
sampleResult:
|
||||
'prefix-apple-suffix,prefix-banana-suffix,prefix-orange-suffix',
|
||||
sampleOptions: {
|
||||
splitOperatorType: 'symbol',
|
||||
splitSeparator: ',',
|
||||
joinSeparator: ',',
|
||||
deleteEmptyItems: true,
|
||||
left: 'prefix-',
|
||||
right: '-suffix'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Wrap({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (optionsValues: InitialValuesType, input: string) => {
|
||||
if (input) {
|
||||
try {
|
||||
setResult(
|
||||
wrapList(
|
||||
optionsValues.splitOperatorType,
|
||||
input,
|
||||
optionsValues.splitSeparator,
|
||||
optionsValues.joinSeparator,
|
||||
optionsValues.deleteEmptyItems,
|
||||
optionsValues.left,
|
||||
optionsValues.right
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
setResult(`Error: ${error.message}`);
|
||||
} else {
|
||||
setResult('An unknown error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Split Options',
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'symbol')}
|
||||
checked={values.splitOperatorType === 'symbol'}
|
||||
title={'Split by Symbol'}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('splitOperatorType', 'regex')}
|
||||
checked={values.splitOperatorType === 'regex'}
|
||||
title={'Split by Regular Expression'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.splitSeparator}
|
||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||
description={'Separator to split the list'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.joinSeparator}
|
||||
onOwnChange={(val) => updateField('joinSeparator', val)}
|
||||
description={'Separator to join the wrapped list'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.deleteEmptyItems}
|
||||
onChange={(checked) => updateField('deleteEmptyItems', checked)}
|
||||
title={'Remove empty items'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Wrap Options',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.left}
|
||||
onOwnChange={(val) => updateField('left', val)}
|
||||
description={'Text to add before each item'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.right}
|
||||
onOwnChange={(val) => updateField('right', val)}
|
||||
description={'Text to add after each item'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input List" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="Wrapped List" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
validationSchema={validationSchema}
|
||||
toolInfo={{
|
||||
title: 'List Wrapping',
|
||||
description:
|
||||
"This tool allows you to add text before and after each item in a list. You can specify different text for the left and right sides, and control how the list is processed. It's useful for adding quotes, brackets, or other formatting to list items, preparing data for different formats, or creating structured text."
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -26,5 +26,8 @@ export const stringTools = [
|
||||
stringUppercase,
|
||||
stringExtractSubstring,
|
||||
stringCreatePalindrome,
|
||||
stringPalindrome
|
||||
stringPalindrome,
|
||||
stringQuote,
|
||||
stringRotate,
|
||||
stringRot13
|
||||
];
|
||||
|
@@ -1,11 +1,149 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { stringQuoter } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Quote() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
interface InitialValuesType {
|
||||
leftQuote: string;
|
||||
rightQuote: string;
|
||||
doubleQuotation: boolean;
|
||||
emptyQuoting: boolean;
|
||||
multiLine: boolean;
|
||||
}
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
leftQuote: '"',
|
||||
rightQuote: '"',
|
||||
doubleQuotation: false,
|
||||
emptyQuoting: true,
|
||||
multiLine: true
|
||||
};
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Quote text with double quotes',
|
||||
description: 'This example shows how to quote text with double quotes.',
|
||||
sampleText: 'Hello World',
|
||||
sampleResult: '"Hello World"',
|
||||
sampleOptions: {
|
||||
leftQuote: '"',
|
||||
rightQuote: '"',
|
||||
doubleQuotation: false,
|
||||
emptyQuoting: true,
|
||||
multiLine: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Quote multi-line text with single quotes',
|
||||
description:
|
||||
'This example shows how to quote multi-line text with single quotes.',
|
||||
sampleText: 'Hello\nWorld',
|
||||
sampleResult: "'Hello'\n'World'",
|
||||
sampleOptions: {
|
||||
leftQuote: "'",
|
||||
rightQuote: "'",
|
||||
doubleQuotation: false,
|
||||
emptyQuoting: true,
|
||||
multiLine: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Quote with custom quotes',
|
||||
description: 'This example shows how to quote text with custom quotes.',
|
||||
sampleText: 'Hello World',
|
||||
sampleResult: '<<Hello World>>',
|
||||
sampleOptions: {
|
||||
leftQuote: '<<',
|
||||
rightQuote: '>>',
|
||||
doubleQuotation: false,
|
||||
emptyQuoting: true,
|
||||
multiLine: false
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Quote({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (optionsValues: InitialValuesType, input: string) => {
|
||||
if (input) {
|
||||
setResult(
|
||||
stringQuoter(
|
||||
input,
|
||||
optionsValues.leftQuote,
|
||||
optionsValues.rightQuote,
|
||||
optionsValues.doubleQuotation,
|
||||
optionsValues.emptyQuoting,
|
||||
optionsValues.multiLine
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Quote Options',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.leftQuote}
|
||||
onOwnChange={(val) => updateField('leftQuote', val)}
|
||||
description={'Left quote character(s)'}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.rightQuote}
|
||||
onOwnChange={(val) => updateField('rightQuote', val)}
|
||||
description={'Right quote character(s)'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.doubleQuotation}
|
||||
onChange={(checked) => updateField('doubleQuotation', checked)}
|
||||
title={'Allow double quotation'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.emptyQuoting}
|
||||
onChange={(checked) => updateField('emptyQuoting', checked)}
|
||||
title={'Quote empty lines'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.multiLine}
|
||||
onChange={(checked) => updateField('multiLine', checked)}
|
||||
title={'Process as multi-line text'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Text" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="Quoted Text" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
toolInfo={{
|
||||
title: 'Text Quoter',
|
||||
description:
|
||||
"This tool allows you to add quotes around text. You can choose different quote characters, handle multi-line text, and control how empty lines are processed. It's useful for preparing text for programming, formatting data, or creating stylized text."
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
@@ -1,11 +1,60 @@
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import React, { useState } from 'react';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { rot13 } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Rot13() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
type InitialValuesType = Record<string, never>;
|
||||
|
||||
const initialValues: InitialValuesType = {};
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Encode a message with ROT13',
|
||||
description:
|
||||
'This example shows how to encode a simple message using ROT13 cipher.',
|
||||
sampleText: 'Hello, World!',
|
||||
sampleResult: 'Uryyb, Jbeyq!',
|
||||
sampleOptions: {}
|
||||
},
|
||||
{
|
||||
title: 'Decode a ROT13 message',
|
||||
description:
|
||||
'This example shows how to decode a message that was encoded with ROT13.',
|
||||
sampleText: 'Uryyb, Jbeyq!',
|
||||
sampleResult: 'Hello, World!',
|
||||
sampleOptions: {}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Rot13({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (_: InitialValuesType, input: string) => {
|
||||
if (input) setResult(rot13(input));
|
||||
};
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Text" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="ROT13 Result" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={null}
|
||||
toolInfo={{
|
||||
title: 'What Is ROT13?',
|
||||
description:
|
||||
'ROT13 (rotate by 13 places) is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. ROT13 is a special case of the Caesar cipher which was developed in ancient Rome. Because there are 26 letters in the English alphabet, ROT13 is its own inverse; that is, to undo ROT13, the same algorithm is applied, so the same action can be used for encoding and decoding.'
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
@@ -1,11 +1,131 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { rotateString } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
|
||||
const initialValues = {};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function Rotate() {
|
||||
return <Box>Lorem ipsum</Box>;
|
||||
interface InitialValuesType {
|
||||
step: string;
|
||||
direction: 'left' | 'right';
|
||||
multiLine: boolean;
|
||||
}
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
step: '1',
|
||||
direction: 'right',
|
||||
multiLine: true
|
||||
};
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Rotate text to the right',
|
||||
description:
|
||||
'This example shows how to rotate text to the right by 2 positions.',
|
||||
sampleText: 'abcdef',
|
||||
sampleResult: 'efabcd',
|
||||
sampleOptions: {
|
||||
step: '2',
|
||||
direction: 'right',
|
||||
multiLine: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Rotate text to the left',
|
||||
description:
|
||||
'This example shows how to rotate text to the left by 2 positions.',
|
||||
sampleText: 'abcdef',
|
||||
sampleResult: 'cdefab',
|
||||
sampleOptions: {
|
||||
step: '2',
|
||||
direction: 'left',
|
||||
multiLine: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Rotate multi-line text',
|
||||
description:
|
||||
'This example shows how to rotate each line of a multi-line text.',
|
||||
sampleText: 'abcdef\nghijkl',
|
||||
sampleResult: 'fabcde\nlghijk',
|
||||
sampleOptions: {
|
||||
step: '1',
|
||||
direction: 'right',
|
||||
multiLine: true
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function Rotate({ title }: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
const compute = (optionsValues: InitialValuesType, input: string) => {
|
||||
if (input) {
|
||||
const step = parseInt(optionsValues.step, 10) || 1;
|
||||
const isRight = optionsValues.direction === 'right';
|
||||
setResult(rotateString(input, step, isRight, optionsValues.multiLine));
|
||||
}
|
||||
};
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Rotation Options',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.step}
|
||||
onOwnChange={(val) => updateField('step', val)}
|
||||
description={'Number of positions to rotate'}
|
||||
type="number"
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('direction', 'right')}
|
||||
checked={values.direction === 'right'}
|
||||
title={'Rotate Right'}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('direction', 'left')}
|
||||
checked={values.direction === 'left'}
|
||||
title={'Rotate Left'}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.multiLine}
|
||||
onChange={(checked) => updateField('multiLine', checked)}
|
||||
title={'Process as multi-line text (rotate each line separately)'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Text" value={input} onChange={setInput} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="Rotated Text" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
toolInfo={{
|
||||
title: 'String Rotation',
|
||||
description:
|
||||
'This tool allows you to rotate characters in a string by a specified number of positions. You can rotate to the left or right, and process multi-line text by rotating each line separately. String rotation is useful for simple text transformations, creating patterns, or implementing basic encryption techniques.'
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
/>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user