mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-12-29 16:16:02 +00:00
refactor: tools folder inside pages
This commit is contained in:
148
src/pages/tools/string/split/index.tsx
Normal file
148
src/pages/tools/string/split/index.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import { Box } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import ToolOptions from '@components/options/ToolOptions';
|
||||
import { compute, SplitOperatorType } from './service';
|
||||
import RadioWithTextField from '@components/options/RadioWithTextField';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
||||
|
||||
const initialValues = {
|
||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||
symbolValue: ' ',
|
||||
regexValue: '/\\s+/',
|
||||
lengthValue: '16',
|
||||
chunksValue: '4',
|
||||
|
||||
outputSeparator: '\\n',
|
||||
charBeforeChunk: '',
|
||||
charAfterChunk: ''
|
||||
};
|
||||
const splitOperators: {
|
||||
title: string;
|
||||
description: string;
|
||||
type: SplitOperatorType;
|
||||
}[] = [
|
||||
{
|
||||
title: 'Use a Symbol for Splitting',
|
||||
description:
|
||||
'Character that will be used to\n' +
|
||||
'break text into parts.\n' +
|
||||
'(Space by default.)',
|
||||
type: 'symbol'
|
||||
},
|
||||
{
|
||||
title: 'Use a Regex for Splitting',
|
||||
type: 'regex',
|
||||
description:
|
||||
'Regular expression that will be\n' +
|
||||
'used to break text into parts.\n' +
|
||||
'(Multiple spaces by default.)'
|
||||
},
|
||||
{
|
||||
title: 'Use Length for Splitting',
|
||||
description:
|
||||
'Number of symbols that will be\n' + 'put in each output chunk.',
|
||||
type: 'length'
|
||||
},
|
||||
{
|
||||
title: 'Use a Number of Chunks',
|
||||
description: 'Number of chunks of equal\n' + 'length in the output.',
|
||||
type: 'chunks'
|
||||
}
|
||||
];
|
||||
const outputOptions: {
|
||||
description: string;
|
||||
accessor: keyof typeof initialValues;
|
||||
}[] = [
|
||||
{
|
||||
description:
|
||||
'Character that will be put\n' +
|
||||
'between the split chunks.\n' +
|
||||
'(It\'s newline "\\n" by default.)',
|
||||
accessor: 'outputSeparator'
|
||||
},
|
||||
{
|
||||
description: 'Character before each chunk',
|
||||
accessor: 'charBeforeChunk'
|
||||
},
|
||||
{
|
||||
description: 'Character after each chunk',
|
||||
accessor: 'charAfterChunk'
|
||||
}
|
||||
];
|
||||
|
||||
export default function SplitText() {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
// const formRef = useRef<FormikProps<typeof initialValues>>(null);
|
||||
const computeExternal = (optionsValues: typeof initialValues, input: any) => {
|
||||
const {
|
||||
splitSeparatorType,
|
||||
outputSeparator,
|
||||
charBeforeChunk,
|
||||
charAfterChunk,
|
||||
chunksValue,
|
||||
symbolValue,
|
||||
regexValue,
|
||||
lengthValue
|
||||
} = optionsValues;
|
||||
|
||||
setResult(
|
||||
compute(
|
||||
splitSeparatorType,
|
||||
input,
|
||||
symbolValue,
|
||||
regexValue,
|
||||
Number(lengthValue),
|
||||
Number(chunksValue),
|
||||
charBeforeChunk,
|
||||
charAfterChunk,
|
||||
outputSeparator
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<ToolInputAndResult
|
||||
input={<ToolTextInput value={input} onChange={setInput} />}
|
||||
result={<ToolTextResult title={'Text pieces'} value={result} />}
|
||||
/>
|
||||
<ToolOptions
|
||||
compute={computeExternal}
|
||||
getGroups={({ values, updateField }) => [
|
||||
{
|
||||
title: 'Split separator options',
|
||||
component: splitOperators.map(({ title, description, type }) => (
|
||||
<RadioWithTextField
|
||||
key={type}
|
||||
checked={type === values.splitSeparatorType}
|
||||
title={title}
|
||||
fieldName={'splitSeparatorType'}
|
||||
description={description}
|
||||
value={values[`${type}Value`]}
|
||||
onRadioClick={() => updateField('splitSeparatorType', type)}
|
||||
onTextChange={(val) => updateField(`${type}Value`, val)}
|
||||
/>
|
||||
))
|
||||
},
|
||||
{
|
||||
title: 'Output separator options',
|
||||
component: outputOptions.map((option) => (
|
||||
<TextFieldWithDesc
|
||||
key={option.accessor}
|
||||
value={values[option.accessor]}
|
||||
onOwnChange={(value) => updateField(option.accessor, value)}
|
||||
description={option.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
]}
|
||||
initialValues={initialValues}
|
||||
input={input}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
14
src/pages/tools/string/split/meta.ts
Normal file
14
src/pages/tools/string/split/meta.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
path: 'split',
|
||||
name: 'Text splitter',
|
||||
image,
|
||||
description:
|
||||
"World's simplest browser-based utility for splitting text. Load your text in the input form on the left and you'll automatically get pieces of this text on the right. Powerful, free, and fast. Load text – get chunks.",
|
||||
shortDescription: 'Quickly split a text',
|
||||
keywords: ['text', 'split'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
65
src/pages/tools/string/split/service.ts
Normal file
65
src/pages/tools/string/split/service.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
export type SplitOperatorType = 'symbol' | 'regex' | 'length' | 'chunks';
|
||||
|
||||
function splitTextByLength(text: string, length: number) {
|
||||
if (length <= 0) throw new Error('Length must be a positive number');
|
||||
const result: string[] = [];
|
||||
for (let i = 0; i < text.length; i += length) {
|
||||
result.push(text.slice(i, i + length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function splitIntoChunks(text: string, numChunks: number) {
|
||||
if (numChunks <= 0)
|
||||
throw new Error('Number of chunks must be a positive number');
|
||||
const totalLength = text.length;
|
||||
if (totalLength < numChunks)
|
||||
throw new Error(
|
||||
'Text length must be at least as long as the number of chunks'
|
||||
);
|
||||
|
||||
const chunkSize = Math.ceil(totalLength / numChunks); // Calculate the chunk size, rounding up to handle remainders
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < totalLength; i += chunkSize) {
|
||||
result.push(text.slice(i, i + chunkSize));
|
||||
}
|
||||
|
||||
// Ensure the result contains exactly numChunks, adjusting the last chunk if necessary
|
||||
if (result.length > numChunks) {
|
||||
result[numChunks - 1] = result.slice(numChunks - 1).join(''); // Merge any extra chunks into the last chunk
|
||||
result = result.slice(0, numChunks); // Take only the first numChunks chunks
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function compute(
|
||||
splitSeparatorType: SplitOperatorType,
|
||||
input: string,
|
||||
symbolValue: string,
|
||||
regexValue: string,
|
||||
lengthValue: number,
|
||||
chunksValue: number,
|
||||
charBeforeChunk: string,
|
||||
charAfterChunk: string,
|
||||
outputSeparator: string
|
||||
) {
|
||||
let splitText;
|
||||
switch (splitSeparatorType) {
|
||||
case 'symbol':
|
||||
splitText = input.split(symbolValue);
|
||||
break;
|
||||
case 'regex':
|
||||
splitText = input.split(new RegExp(regexValue));
|
||||
break;
|
||||
case 'length':
|
||||
splitText = splitTextByLength(input, lengthValue);
|
||||
break;
|
||||
case 'chunks':
|
||||
splitText = splitIntoChunks(input, chunksValue).map(
|
||||
(chunk) => `${charBeforeChunk}${chunk}${charAfterChunk}`
|
||||
);
|
||||
}
|
||||
return splitText.join(outputSeparator);
|
||||
}
|
||||
72
src/pages/tools/string/split/string-split.service.test.ts
Normal file
72
src/pages/tools/string/split/string-split.service.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { compute } from './service';
|
||||
|
||||
describe('compute function', () => {
|
||||
it('should split by symbol', () => {
|
||||
const result = compute('symbol', 'hello world', ' ', '', 0, 0, '', '', ',');
|
||||
expect(result).toBe('hello,world');
|
||||
});
|
||||
|
||||
it('should split by regex', () => {
|
||||
const result = compute(
|
||||
'regex',
|
||||
'hello1world2again',
|
||||
'',
|
||||
'\\d',
|
||||
0,
|
||||
0,
|
||||
'',
|
||||
'',
|
||||
','
|
||||
);
|
||||
expect(result).toBe('hello,world,again');
|
||||
});
|
||||
|
||||
it('should split by length', () => {
|
||||
const result = compute('length', 'helloworld', '', '', 3, 0, '', '', ',');
|
||||
expect(result).toBe('hel,low,orl,d');
|
||||
});
|
||||
|
||||
it('should split into chunks', () => {
|
||||
const result = compute(
|
||||
'chunks',
|
||||
'helloworldagain',
|
||||
'',
|
||||
'',
|
||||
0,
|
||||
3,
|
||||
'[',
|
||||
']',
|
||||
','
|
||||
);
|
||||
expect(result).toBe('[hello],[world],[again]');
|
||||
});
|
||||
|
||||
it('should handle empty input', () => {
|
||||
const result = compute('symbol', '', ' ', '', 0, 0, '', '', ',');
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should handle length greater than text length', () => {
|
||||
const result = compute('length', 'hi', '', '', 5, 0, '', '', ',');
|
||||
expect(result).toBe('hi');
|
||||
});
|
||||
|
||||
it('should handle chunks greater than text length', () => {
|
||||
expect(() => {
|
||||
compute('chunks', 'hi', '', '', 0, 5, '', '', ',');
|
||||
}).toThrow('Text length must be at least as long as the number of chunks');
|
||||
});
|
||||
|
||||
it('should handle invalid length', () => {
|
||||
expect(() => {
|
||||
compute('length', 'hello', '', '', -1, 0, '', '', ',');
|
||||
}).toThrow('Length must be a positive number');
|
||||
});
|
||||
|
||||
it('should handle invalid chunks', () => {
|
||||
expect(() => {
|
||||
compute('chunks', 'hello', '', '', 0, 0, '', '', ',');
|
||||
}).toThrow('Number of chunks must be a positive number');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user