diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 903f932..d9ee357 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,15 +4,18 @@
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
@@ -111,53 +114,53 @@
- {
+ "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"
}
-}]]>
+}
-
+
@@ -256,10 +259,10 @@
+
-
@@ -340,15 +343,7 @@
-
-
-
-
- 1740322444616
-
-
-
- 1740322444616
+
@@ -734,7 +729,15 @@
1741535390090
-
+
+
+ 1741540939154
+
+
+
+ 1741540939154
+
+
@@ -781,7 +784,6 @@
-
@@ -806,7 +808,8 @@
-
+
+
diff --git a/src/components/options/CheckboxWithDesc.tsx b/src/components/options/CheckboxWithDesc.tsx
index 3f39c77..e991c3a 100644
--- a/src/components/options/CheckboxWithDesc.tsx
+++ b/src/components/options/CheckboxWithDesc.tsx
@@ -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}
/>
-
- {description}
-
+ {description && (
+
+ {description}
+
+ )}
);
};
diff --git a/src/pages/tools/list/duplicate/index.tsx b/src/pages/tools/list/duplicate/index.tsx
index 4427588..9e4f50c 100644
--- a/src/pages/tools/list/duplicate/index.tsx
+++ b/src/pages/tools/list/duplicate/index.tsx
@@ -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 Lorem ipsum;
+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[] = [
+ {
+ 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('');
+ const [result, setResult] = useState('');
+
+ 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 = ({
+ values,
+ updateField
+ }) => [
+ {
+ title: 'Split Options',
+ component: (
+
+ updateField('splitOperatorType', 'symbol')}
+ checked={values.splitOperatorType === 'symbol'}
+ title={'Split by Symbol'}
+ />
+ updateField('splitOperatorType', 'regex')}
+ checked={values.splitOperatorType === 'regex'}
+ title={'Split by Regular Expression'}
+ />
+ updateField('splitSeparator', val)}
+ description={'Separator to split the list'}
+ />
+ updateField('joinSeparator', val)}
+ description={'Separator to join the duplicated list'}
+ />
+
+ )
+ },
+ {
+ title: 'Duplication Options',
+ component: (
+
+ updateField('copy', val)}
+ description={'Number of copies (can be fractional)'}
+ type="number"
+ />
+ updateField('concatenate', checked)}
+ description={
+ 'Concatenate copies (if unchecked, items will be interweaved)'
+ }
+ />
+ updateField('reverse', checked)}
+ description={'Reverse the duplicated items'}
+ />
+
+ )
+ }
+ ];
+
+ return (
+
+ }
+ resultComponent={
+
+ }
+ 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}
+ />
+ );
}
diff --git a/src/pages/tools/list/index.ts b/src/pages/tools/list/index.ts
index 0ea2f7c..d66d283 100644
--- a/src/pages/tools/list/index.ts
+++ b/src/pages/tools/list/index.ts
@@ -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
];
diff --git a/src/pages/tools/list/truncate/index.tsx b/src/pages/tools/list/truncate/index.tsx
index f46ad17..c648623 100644
--- a/src/pages/tools/list/truncate/index.tsx
+++ b/src/pages/tools/list/truncate/index.tsx
@@ -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 Lorem ipsum;
+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[] = [
+ {
+ 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('');
+ const [result, setResult] = useState('');
+
+ 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 = ({
+ values,
+ updateField
+ }) => [
+ {
+ title: 'Split Options',
+ component: (
+
+ updateField('splitOperatorType', 'symbol')}
+ checked={values.splitOperatorType === 'symbol'}
+ title={'Split by Symbol'}
+ />
+ updateField('splitOperatorType', 'regex')}
+ checked={values.splitOperatorType === 'regex'}
+ title={'Split by Regular Expression'}
+ />
+ updateField('splitSeparator', val)}
+ description={'Separator to split the list'}
+ />
+ updateField('joinSeparator', val)}
+ description={'Separator to join the truncated list'}
+ />
+
+ )
+ },
+ {
+ title: 'Truncation Options',
+ component: (
+
+ updateField('length', val)}
+ description={'Number of items to keep'}
+ type="number"
+ />
+ updateField('end', true)}
+ checked={values.end}
+ title={'Keep items from the beginning'}
+ />
+ updateField('end', false)}
+ checked={!values.end}
+ title={'Keep items from the end'}
+ />
+
+ )
+ }
+ ];
+
+ return (
+
+ }
+ resultComponent={}
+ 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}
+ />
+ );
}
diff --git a/src/pages/tools/list/unwrap/index.tsx b/src/pages/tools/list/unwrap/index.tsx
index 3c4b34d..2ad7083 100644
--- a/src/pages/tools/list/unwrap/index.tsx
+++ b/src/pages/tools/list/unwrap/index.tsx
@@ -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 Lorem ipsum;
+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[] = [
+ {
+ 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('');
+ const [result, setResult] = useState('');
+
+ 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 = ({
+ values,
+ updateField
+ }) => [
+ {
+ title: 'Split Options',
+ component: (
+
+ updateField('splitOperatorType', 'symbol')}
+ checked={values.splitOperatorType === 'symbol'}
+ title={'Split by Symbol'}
+ />
+ updateField('splitOperatorType', 'regex')}
+ checked={values.splitOperatorType === 'regex'}
+ title={'Split by Regular Expression'}
+ />
+ updateField('splitSeparator', val)}
+ description={'Separator to split the list'}
+ />
+ updateField('joinSeparator', val)}
+ description={'Separator to join the unwrapped list'}
+ />
+
+ )
+ },
+ {
+ title: 'Unwrap Options',
+ component: (
+
+ updateField('left', val)}
+ description={'Characters to remove from the left side'}
+ />
+ updateField('right', val)}
+ description={'Characters to remove from the right side'}
+ />
+ updateField('multiLevel', checked)}
+ title={'Remove multiple levels of wrapping'}
+ />
+ updateField('trimItems', checked)}
+ title={'Trim whitespace from items'}
+ />
+ updateField('deleteEmptyItems', checked)}
+ title={'Remove empty items'}
+ />
+
+ )
+ }
+ ];
+
+ return (
+
+ }
+ resultComponent={}
+ 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}
+ />
+ );
}
diff --git a/src/pages/tools/list/wrap/index.tsx b/src/pages/tools/list/wrap/index.tsx
index 426bd94..dec2ae7 100644
--- a/src/pages/tools/list/wrap/index.tsx
+++ b/src/pages/tools/list/wrap/index.tsx
@@ -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 Lorem ipsum;
+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[] = [
+ {
+ 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('');
+ const [result, setResult] = useState('');
+
+ 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 = ({
+ values,
+ updateField
+ }) => [
+ {
+ title: 'Split Options',
+ component: (
+
+ updateField('splitOperatorType', 'symbol')}
+ checked={values.splitOperatorType === 'symbol'}
+ title={'Split by Symbol'}
+ />
+ updateField('splitOperatorType', 'regex')}
+ checked={values.splitOperatorType === 'regex'}
+ title={'Split by Regular Expression'}
+ />
+ updateField('splitSeparator', val)}
+ description={'Separator to split the list'}
+ />
+ updateField('joinSeparator', val)}
+ description={'Separator to join the wrapped list'}
+ />
+ updateField('deleteEmptyItems', checked)}
+ title={'Remove empty items'}
+ />
+
+ )
+ },
+ {
+ title: 'Wrap Options',
+ component: (
+
+ updateField('left', val)}
+ description={'Text to add before each item'}
+ />
+ updateField('right', val)}
+ description={'Text to add after each item'}
+ />
+
+ )
+ }
+ ];
+
+ return (
+
+ }
+ resultComponent={}
+ 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}
+ />
+ );
}
diff --git a/src/pages/tools/string/index.ts b/src/pages/tools/string/index.ts
index 24f6939..f9ba4ec 100644
--- a/src/pages/tools/string/index.ts
+++ b/src/pages/tools/string/index.ts
@@ -26,5 +26,8 @@ export const stringTools = [
stringUppercase,
stringExtractSubstring,
stringCreatePalindrome,
- stringPalindrome
+ stringPalindrome,
+ stringQuote,
+ stringRotate,
+ stringRot13
];
diff --git a/src/pages/tools/string/quote/index.tsx b/src/pages/tools/string/quote/index.tsx
index ece5985..61035a0 100644
--- a/src/pages/tools/string/quote/index.tsx
+++ b/src/pages/tools/string/quote/index.tsx
@@ -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 Lorem ipsum;
-}
\ No newline at end of file
+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[] = [
+ {
+ 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: '<>',
+ sampleOptions: {
+ leftQuote: '<<',
+ rightQuote: '>>',
+ doubleQuotation: false,
+ emptyQuoting: true,
+ multiLine: false
+ }
+ }
+];
+
+export default function Quote({ title }: ToolComponentProps) {
+ const [input, setInput] = useState('');
+ const [result, setResult] = useState('');
+
+ const compute = (optionsValues: InitialValuesType, input: string) => {
+ if (input) {
+ setResult(
+ stringQuoter(
+ input,
+ optionsValues.leftQuote,
+ optionsValues.rightQuote,
+ optionsValues.doubleQuotation,
+ optionsValues.emptyQuoting,
+ optionsValues.multiLine
+ )
+ );
+ }
+ };
+
+ const getGroups: GetGroupsType = ({
+ values,
+ updateField
+ }) => [
+ {
+ title: 'Quote Options',
+ component: (
+
+ updateField('leftQuote', val)}
+ description={'Left quote character(s)'}
+ />
+ updateField('rightQuote', val)}
+ description={'Right quote character(s)'}
+ />
+ updateField('doubleQuotation', checked)}
+ title={'Allow double quotation'}
+ />
+ updateField('emptyQuoting', checked)}
+ title={'Quote empty lines'}
+ />
+ updateField('multiLine', checked)}
+ title={'Process as multi-line text'}
+ />
+
+ )
+ }
+ ];
+
+ return (
+
+ }
+ resultComponent={}
+ 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}
+ />
+ );
+}
diff --git a/src/pages/tools/string/rot13/index.tsx b/src/pages/tools/string/rot13/index.tsx
index 2814f13..eae341f 100644
--- a/src/pages/tools/string/rot13/index.tsx
+++ b/src/pages/tools/string/rot13/index.tsx
@@ -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 Lorem ipsum;
-}
\ No newline at end of file
+type InitialValuesType = Record;
+
+const initialValues: InitialValuesType = {};
+
+const exampleCards: CardExampleType[] = [
+ {
+ 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('');
+ const [result, setResult] = useState('');
+
+ const compute = (_: InitialValuesType, input: string) => {
+ if (input) setResult(rot13(input));
+ };
+
+ return (
+
+ }
+ resultComponent={}
+ 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}
+ />
+ );
+}
diff --git a/src/pages/tools/string/rotate/index.tsx b/src/pages/tools/string/rotate/index.tsx
index ea7d7d5..df19411 100644
--- a/src/pages/tools/string/rotate/index.tsx
+++ b/src/pages/tools/string/rotate/index.tsx
@@ -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 Lorem ipsum;
-}
\ No newline at end of file
+interface InitialValuesType {
+ step: string;
+ direction: 'left' | 'right';
+ multiLine: boolean;
+}
+
+const initialValues: InitialValuesType = {
+ step: '1',
+ direction: 'right',
+ multiLine: true
+};
+
+const exampleCards: CardExampleType[] = [
+ {
+ 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('');
+ const [result, setResult] = useState('');
+
+ 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 = ({
+ values,
+ updateField
+ }) => [
+ {
+ title: 'Rotation Options',
+ component: (
+
+ updateField('step', val)}
+ description={'Number of positions to rotate'}
+ type="number"
+ />
+ updateField('direction', 'right')}
+ checked={values.direction === 'right'}
+ title={'Rotate Right'}
+ />
+ updateField('direction', 'left')}
+ checked={values.direction === 'left'}
+ title={'Rotate Left'}
+ />
+ updateField('multiLine', checked)}
+ title={'Process as multi-line text (rotate each line separately)'}
+ />
+
+ )
+ }
+ ];
+
+ return (
+
+ }
+ resultComponent={}
+ 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}
+ />
+ );
+}