mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-12-29 16:16:02 +00:00
Merge branch 'main' into tools-filtering
This commit is contained in:
@@ -9,6 +9,7 @@ import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import { Box } from '@mui/material';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import { InitialValuesType } from './types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
mode: 'encode'
|
||||
@@ -33,6 +34,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
];
|
||||
|
||||
export default function Base64({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -45,18 +47,18 @@ export default function Base64({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Base64 Options',
|
||||
title: t('base64.optionsTitle'),
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('mode', 'encode')}
|
||||
checked={values.mode === 'encode'}
|
||||
title={'Base64 Encode'}
|
||||
title={t('base64.encode')}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('mode', 'decode')}
|
||||
checked={values.mode === 'decode'}
|
||||
title={'Base64 Decode'}
|
||||
title={t('base64.decode')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
@@ -67,15 +69,20 @@ export default function Base64({ title }: ToolComponentProps) {
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Data" value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('base64.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('base64.resultTitle')} value={result} />
|
||||
}
|
||||
resultComponent={<ToolTextResult title="Result" value={result} />}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
toolInfo={{
|
||||
title: 'What is Base64?',
|
||||
description:
|
||||
'Base64 is an encoding scheme that represents data in an ASCII string format by translating it into a radix-64 representation. Although it can be used to encode strings, it is commonly used to encode binary data for transmission over media that are designed to deal with textual data.'
|
||||
title: t('base64.toolInfo.title'),
|
||||
description: t('base64.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
|
||||
@@ -2,13 +2,15 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Base64',
|
||||
path: 'base64',
|
||||
icon: 'tabler:number-64-small',
|
||||
description:
|
||||
'A simple tool to encode or decode data using Base64, which is commonly used in web applications.',
|
||||
shortDescription: 'Encode or decode data using Base64.',
|
||||
|
||||
keywords: ['base64'],
|
||||
userTypes: ['Developers', 'CyberSec'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:base64.title',
|
||||
description: 'string:base64.description',
|
||||
shortDescription: 'string:base64.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,16 +2,16 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Text Censor',
|
||||
path: 'censor',
|
||||
shortDescription:
|
||||
'Quickly mask bad words or replace them with alternative words.',
|
||||
|
||||
icon: 'hugeicons:text-footnote',
|
||||
description:
|
||||
"utility for censoring words in text. Load your text in the input form on the left, specify all the bad words in the options, and you'll instantly get censored text in the output area.",
|
||||
longDescription:
|
||||
'With this online tool, you can censor certain words in any text. You can specify a list of unwanted words (such as swear words or secret words) and the program will replace them with alternative words and create a safe-to-read text. The words can be specified in a multi-line text field in the options by entering one word per line.',
|
||||
|
||||
keywords: ['text', 'censor', 'words', 'characters'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:censor.title',
|
||||
description: 'string:censor.description',
|
||||
shortDescription: 'string:censor.shortDescription',
|
||||
userTypes: ['General Users', 'Students']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,15 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Create palindrome',
|
||||
path: 'create-palindrome',
|
||||
icon: 'material-symbols-light:repeat',
|
||||
description:
|
||||
"World's simplest browser-based utility for creating palindromes from any text. Input text and instantly transform it into a palindrome that reads the same forward and backward. Perfect for word games, creating symmetrical text patterns, or exploring linguistic curiosities.",
|
||||
shortDescription: 'Create text that reads the same forward and backward',
|
||||
longDescription:
|
||||
'This tool creates a palindrome from the given string. It does it by generating a copy of the string, reversing it, and appending it at the end of the original string. This method creates a palindrome with the last character duplicated twice. There is also another way to do it, which deletes the first letter of the reversed copy. In this case, when the string and the copy are joined together, you also get a palindrome but without the repeating last character. You can compare the two types of palindromes by switching between them in the options. You can also enable the multi-line mode that will create palindromes of every string on every line. Stringabulous!',
|
||||
|
||||
keywords: ['create', 'palindrome'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:createPalindrome.title',
|
||||
description: 'string:createPalindrome.description',
|
||||
shortDescription: 'string:createPalindrome.shortDescription',
|
||||
userTypes: ['General Users', 'Students']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,13 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Extract substring',
|
||||
path: 'extract-substring',
|
||||
icon: 'material-symbols-light:content-cut',
|
||||
description:
|
||||
"World's simplest browser-based utility for extracting substrings from text. Easily extract specific portions of text by specifying start position and length. Perfect for parsing data, isolating specific parts of text, or data extraction tasks. Supports multi-line text processing and character-level precision.",
|
||||
shortDescription: 'Extract specific portions of text by position and length',
|
||||
|
||||
keywords: ['extract', 'substring'],
|
||||
userTypes: ['General Users', 'Students', 'Developers'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:extractSubstring.title',
|
||||
description: 'string:extractSubstring.description',
|
||||
shortDescription: 'string:extractSubstring.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import { tool as stringTruncate } from './truncate/meta';
|
||||
import { tool as stringBase64 } from './base64/meta';
|
||||
import { tool as stringStatistic } from './statistic/meta';
|
||||
import { tool as stringCensor } from './censor/meta';
|
||||
import { tool as stringPasswordGenerator } from './password-generator/meta';
|
||||
|
||||
export const stringTools = [
|
||||
stringSplit,
|
||||
@@ -37,5 +38,6 @@ export const stringTools = [
|
||||
stringRot13,
|
||||
stringBase64,
|
||||
stringStatistic,
|
||||
stringCensor
|
||||
stringCensor,
|
||||
stringPasswordGenerator
|
||||
];
|
||||
|
||||
@@ -9,6 +9,7 @@ import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const initialValues = {
|
||||
joinCharacter: '',
|
||||
@@ -32,7 +33,7 @@ const mergeOptions = {
|
||||
const blankTrailingOptions: {
|
||||
title: string;
|
||||
description: string;
|
||||
accessor: keyof InitialValuesType;
|
||||
accessor: keyof Omit<InitialValuesType, 'joinCharacter'>;
|
||||
}[] = [
|
||||
{
|
||||
title: 'Delete Blank Lines',
|
||||
@@ -107,6 +108,7 @@ s
|
||||
];
|
||||
|
||||
export default function JoinText({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
const compute = (optionsValues: InitialValuesType, input: any) => {
|
||||
@@ -119,25 +121,25 @@ export default function JoinText({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Text Merged Options',
|
||||
title: t('join.textMergedOptions'),
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
placeholder={mergeOptions.placeholder}
|
||||
placeholder={t('join.joinCharacterPlaceholder')}
|
||||
value={values['joinCharacter']}
|
||||
onOwnChange={(value) => updateField(mergeOptions.accessor, value)}
|
||||
description={mergeOptions.description}
|
||||
description={t('join.joinCharacterDescription')}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Blank Lines and Trailing Spaces',
|
||||
title: t('join.blankLinesAndTrailingSpaces'),
|
||||
component: blankTrailingOptions.map((option) => (
|
||||
<CheckboxWithDesc
|
||||
key={option.accessor}
|
||||
title={option.title}
|
||||
title={t(`join.${option.accessor}Title`)}
|
||||
checked={!!values[option.accessor]}
|
||||
onChange={(value) => updateField(option.accessor, value)}
|
||||
description={option.description}
|
||||
description={t(`join.${option.accessor}Description`)}
|
||||
/>
|
||||
))
|
||||
}
|
||||
@@ -151,17 +153,18 @@ export default function JoinText({ title }: ToolComponentProps) {
|
||||
setInput={setInput}
|
||||
inputComponent={
|
||||
<ToolTextInput
|
||||
title={'Text Pieces'}
|
||||
title={t('join.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={<ToolTextResult title={'Joined Text'} value={result} />}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('join.resultTitle')} value={result} />
|
||||
}
|
||||
getGroups={getGroups}
|
||||
toolInfo={{
|
||||
title: 'What Is a Text Joiner?',
|
||||
description:
|
||||
'With this tool you can join parts of the text together. It takes a list of text values, separated by newlines, and merges them together. You can set the character that will be placed between the parts of the combined text. Also, you can ignore all empty lines and remove spaces and tabs at the end of all lines. Textabulous!'
|
||||
title: t('join.toolInfo.title'),
|
||||
description: t('join.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
|
||||
@@ -3,12 +3,15 @@ import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
path: 'join',
|
||||
name: 'Text Joiner',
|
||||
icon: 'tabler:arrows-join',
|
||||
description:
|
||||
"World's Simplest Text Tool World's simplest browser-based utility for joining text. Load your text in the input form on the left and you'll automatically get merged text on the right. Powerful, free, and fast. Load text – get joined lines",
|
||||
shortDescription: 'Quickly merge texts',
|
||||
|
||||
icon: 'material-symbols-light:join',
|
||||
|
||||
keywords: ['text', 'join'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:join.title',
|
||||
description: 'string:join.description',
|
||||
shortDescription: 'string:join.shortDescription',
|
||||
userTypes: ['General Users', 'Students']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,13 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Palindrome',
|
||||
path: 'palindrome',
|
||||
icon: 'material-symbols-light:search',
|
||||
description:
|
||||
"World's simplest browser-based utility for checking if text is a palindrome. Instantly verify if your text reads the same forward and backward. Perfect for word puzzles, linguistic analysis, or validating symmetrical text patterns. Supports various delimiters and multi-word palindrome detection.",
|
||||
shortDescription: 'Check if text reads the same forward and backward',
|
||||
|
||||
keywords: ['palindrome'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:palindrome.title',
|
||||
description: 'string:palindrome.description',
|
||||
shortDescription: 'string:palindrome.shortDescription',
|
||||
userTypes: ['General Users', 'Students']
|
||||
}
|
||||
});
|
||||
|
||||
165
src/pages/tools/string/password-generator/index.tsx
Normal file
165
src/pages/tools/string/password-generator/index.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Checkbox, FormControlLabel, FormGroup } from '@mui/material';
|
||||
import { generatePassword } from './service';
|
||||
import { initialValues, InitialValuesType } from './initialValues';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Strong Password (12 characters)',
|
||||
description:
|
||||
'Generate a secure password with all character types including symbols.',
|
||||
sampleText: '',
|
||||
sampleResult: 'A7#mK9$pL2@x',
|
||||
sampleOptions: {
|
||||
length: '12',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Simple Password (8 characters)',
|
||||
description: 'Generate a basic password with letters and numbers only.',
|
||||
sampleText: '',
|
||||
sampleResult: 'Ab3mK9pL',
|
||||
sampleOptions: {
|
||||
length: '8',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: false,
|
||||
avoidAmbiguous: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Clear Password (No ambiguous)',
|
||||
description:
|
||||
'Generate a password without ambiguous characters (i, I, l, 0, O).',
|
||||
sampleText: '',
|
||||
sampleResult: 'A7#mK9$pL2@x',
|
||||
sampleOptions: {
|
||||
length: '12',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: true
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function PasswordGenerator({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
function compute(values: InitialValuesType) {
|
||||
setResult(generatePassword(values));
|
||||
}
|
||||
|
||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||
values,
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: t('passwordGenerator.optionsTitle'),
|
||||
component: (
|
||||
<Box sx={{ display: 'flex', gap: 2, flexDirection: 'column' }}>
|
||||
<TextFieldWithDesc
|
||||
description={t('passwordGenerator.lengthDesc')}
|
||||
placeholder={t('passwordGenerator.lengthPlaceholder')}
|
||||
value={values.length}
|
||||
onOwnChange={(val) => updateField('length', val)}
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeLowercase}
|
||||
onChange={(e) =>
|
||||
updateField('includeLowercase', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeLowercase')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeUppercase}
|
||||
onChange={(e) =>
|
||||
updateField('includeUppercase', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeUppercase')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeNumbers}
|
||||
onChange={(e) =>
|
||||
updateField('includeNumbers', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeNumbers')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.includeSymbols}
|
||||
onChange={(e) =>
|
||||
updateField('includeSymbols', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.includeSymbols')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.avoidAmbiguous}
|
||||
onChange={(e) =>
|
||||
updateField('avoidAmbiguous', e.target.checked)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={t('passwordGenerator.avoidAmbiguous')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
initialValues={initialValues}
|
||||
getGroups={getGroups}
|
||||
compute={compute}
|
||||
resultComponent={
|
||||
<ToolTextResult
|
||||
title={t('passwordGenerator.resultTitle')}
|
||||
value={result}
|
||||
/>
|
||||
}
|
||||
toolInfo={{
|
||||
title: t('passwordGenerator.toolInfo.title'),
|
||||
description: t('passwordGenerator.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
);
|
||||
}
|
||||
17
src/pages/tools/string/password-generator/initialValues.ts
Normal file
17
src/pages/tools/string/password-generator/initialValues.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export type InitialValuesType = {
|
||||
length: string; // user enters a number here
|
||||
includeLowercase: boolean;
|
||||
includeUppercase: boolean;
|
||||
includeNumbers: boolean;
|
||||
includeSymbols: boolean;
|
||||
avoidAmbiguous: boolean;
|
||||
};
|
||||
|
||||
export const initialValues: InitialValuesType = {
|
||||
length: '12',
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: false
|
||||
};
|
||||
14
src/pages/tools/string/password-generator/meta.ts
Normal file
14
src/pages/tools/string/password-generator/meta.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
path: 'password-generator',
|
||||
icon: 'material-symbols:key',
|
||||
keywords: ['password', 'generator', 'random', 'secure'],
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:passwordGenerator.title',
|
||||
description: 'string:passwordGenerator.description',
|
||||
shortDescription: 'string:passwordGenerator.shortDescription'
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,143 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { generatePassword } from './service';
|
||||
import { initialValues } from './initialValues';
|
||||
|
||||
describe('generatePassword', () => {
|
||||
it('should generate a password with the specified length', () => {
|
||||
const options = { ...initialValues, length: '10' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toHaveLength(10);
|
||||
});
|
||||
|
||||
it('should return empty string for invalid length', () => {
|
||||
const options = { ...initialValues, length: '0' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string for non-numeric length', () => {
|
||||
const options = { ...initialValues, length: 'abc' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string when no character types are selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: false,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should only include lowercase letters when only lowercase is selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '20',
|
||||
includeLowercase: true,
|
||||
includeUppercase: false,
|
||||
includeNumbers: false,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[a-z]+$/);
|
||||
expect(result).toHaveLength(20);
|
||||
});
|
||||
|
||||
it('should only include uppercase letters when only uppercase is selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '15',
|
||||
includeLowercase: false,
|
||||
includeUppercase: true,
|
||||
includeNumbers: false,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[A-Z]+$/);
|
||||
expect(result).toHaveLength(15);
|
||||
});
|
||||
|
||||
it('should only include numbers when only numbers is selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '8',
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: true,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[0-9]+$/);
|
||||
expect(result).toHaveLength(8);
|
||||
});
|
||||
|
||||
it('should include mixed character types when multiple are selected', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '100', // larger sample for better testing
|
||||
includeLowercase: true,
|
||||
includeUppercase: true,
|
||||
includeNumbers: true,
|
||||
includeSymbols: false
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[a-zA-Z0-9]+$/);
|
||||
expect(result).toHaveLength(100);
|
||||
});
|
||||
|
||||
it('should exclude ambiguous characters when avoidAmbiguous is true', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '50',
|
||||
avoidAmbiguous: true
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).not.toMatch(/[iIl0O]/);
|
||||
expect(result).toHaveLength(50);
|
||||
});
|
||||
|
||||
it('should include symbols when includeSymbols is true', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '30',
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: false,
|
||||
includeSymbols: true
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).toMatch(/^[!@#$%^&*()_+~`|}{[\]:;?><,./\-=]+$/);
|
||||
expect(result).toHaveLength(30);
|
||||
});
|
||||
|
||||
it('should exclude ambiguous characters from symbols too', () => {
|
||||
const options = {
|
||||
...initialValues,
|
||||
length: '50',
|
||||
includeLowercase: false,
|
||||
includeUppercase: false,
|
||||
includeNumbers: true,
|
||||
includeSymbols: true,
|
||||
avoidAmbiguous: true
|
||||
};
|
||||
const result = generatePassword(options);
|
||||
expect(result).not.toMatch(/[iIl0O]/);
|
||||
expect(result).toHaveLength(50);
|
||||
});
|
||||
|
||||
it('should handle edge case with very short length', () => {
|
||||
const options = { ...initialValues, length: '1' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should handle negative length', () => {
|
||||
const options = { ...initialValues, length: '-5' };
|
||||
const result = generatePassword(options);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
});
|
||||
38
src/pages/tools/string/password-generator/service.ts
Normal file
38
src/pages/tools/string/password-generator/service.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { InitialValuesType } from './initialValues';
|
||||
|
||||
export function generatePassword(options: InitialValuesType): string {
|
||||
const length = parseInt(options.length || '', 10);
|
||||
if (isNaN(length) || length <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let charset = '';
|
||||
const lower = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
const numbers = '0123456789';
|
||||
const symbols = '!@#$%^&*()_+~`|}{[]:;?><,./-=';
|
||||
|
||||
if (options.includeLowercase) charset += lower;
|
||||
if (options.includeUppercase) charset += upper;
|
||||
if (options.includeNumbers) charset += numbers;
|
||||
if (options.includeSymbols) charset += symbols;
|
||||
|
||||
if (options.avoidAmbiguous) {
|
||||
// ambiguous set = i, I, l, 0, O
|
||||
const ambig = new Set(['i', 'I', 'l', '0', 'O']);
|
||||
charset = Array.from(charset)
|
||||
.filter((c) => !ambig.has(c))
|
||||
.join('');
|
||||
}
|
||||
|
||||
if (!charset) {
|
||||
return ''; // nothing to pick from
|
||||
}
|
||||
|
||||
let pwd = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
const idx = Math.floor(Math.random() * charset.length);
|
||||
pwd += charset[idx];
|
||||
}
|
||||
return pwd;
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface InitialValuesType {
|
||||
leftQuote: string;
|
||||
@@ -70,6 +71,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
];
|
||||
|
||||
export default function Quote({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -93,33 +95,33 @@ export default function Quote({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Quote Options',
|
||||
title: t('quote.quoteOptions'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.leftQuote}
|
||||
onOwnChange={(val) => updateField('leftQuote', val)}
|
||||
description={'Left quote character(s)'}
|
||||
description={t('quote.leftQuoteDescription')}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.rightQuote}
|
||||
onOwnChange={(val) => updateField('rightQuote', val)}
|
||||
description={'Right quote character(s)'}
|
||||
description={t('quote.rightQuoteDescription')}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.doubleQuotation}
|
||||
onChange={(checked) => updateField('doubleQuotation', checked)}
|
||||
title={'Allow double quotation'}
|
||||
title={t('quote.allowDoubleQuotation')}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.emptyQuoting}
|
||||
onChange={(checked) => updateField('emptyQuoting', checked)}
|
||||
title={'Quote empty lines'}
|
||||
title={t('quote.quoteEmptyLines')}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.multiLine}
|
||||
onChange={(checked) => updateField('multiLine', checked)}
|
||||
title={'Process as multi-line text'}
|
||||
title={t('quote.processAsMultiLine')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
@@ -130,15 +132,20 @@ export default function Quote({ title }: ToolComponentProps) {
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Text" value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('quote.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('quote.resultTitle')} value={result} />
|
||||
}
|
||||
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."
|
||||
title: t('quote.toolInfo.title'),
|
||||
description: t('quote.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
|
||||
@@ -3,13 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Quote',
|
||||
path: 'quote',
|
||||
icon: 'proicons:quote',
|
||||
description:
|
||||
'A tool to add quotation marks or custom characters around text. Perfect for formatting strings for code, citations, or stylistic purposes.',
|
||||
shortDescription: 'Add quotes around text easily.',
|
||||
icon: 'material-symbols-light:format-quote',
|
||||
|
||||
keywords: ['quote'],
|
||||
userTypes: ['General Users', 'Students', 'Developers'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:quote.title',
|
||||
description: 'string:quote.description',
|
||||
shortDescription: 'string:quote.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,13 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Randomize case',
|
||||
path: 'randomize-case',
|
||||
icon: 'material-symbols-light:format-textdirection-l-to-r',
|
||||
description:
|
||||
"World's simplest browser-based utility for randomizing the case of text. Just paste your text and get it instantly transformed with random uppercase and lowercase letters. Perfect for creating playful text styles, meme text, or simulating chaotic writing.",
|
||||
shortDescription: 'Convert text to random uppercase and lowercase letters',
|
||||
icon: 'material-symbols-light:shuffle',
|
||||
|
||||
keywords: ['randomize', 'case'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:randomizeCase.title',
|
||||
description: 'string:randomizeCase.description',
|
||||
shortDescription: 'string:randomizeCase.shortDescription',
|
||||
userTypes: ['General Users', 'Students']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,13 +2,15 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Remove duplicate lines',
|
||||
path: 'remove-duplicate-lines',
|
||||
icon: 'pepicons-print:duplicate-off',
|
||||
description:
|
||||
"Load your text in the input form on the left and you'll instantly get text with no duplicate lines in the output area. Powerful, free, and fast. Load text lines – get unique text lines",
|
||||
shortDescription: 'Quickly delete all repeated lines from text',
|
||||
|
||||
keywords: ['remove', 'duplicate', 'lines'],
|
||||
userTypes: ['General Users', 'Students', 'Developers'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:removeDuplicateLines.title',
|
||||
description: 'string:removeDuplicateLines.description',
|
||||
shortDescription: 'string:removeDuplicateLines.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import { initialValues, InitialValuesType } from './initialValues';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
@@ -48,6 +49,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
];
|
||||
|
||||
export default function Replacer({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -60,12 +62,12 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Text Repetitions',
|
||||
title: t('repeat.textRepetitions'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
description={'Number of repetitions.'}
|
||||
placeholder="Number"
|
||||
description={t('repeat.repeatAmountDescription')}
|
||||
placeholder={t('repeat.numberPlaceholder')}
|
||||
value={values.repeatAmount}
|
||||
onOwnChange={(val) => updateField('repeatAmount', val)}
|
||||
type={'number'}
|
||||
@@ -74,12 +76,12 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Repetitions Delimiter',
|
||||
title: t('repeat.repetitionsDelimiter'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
description={'Delimiter for output copies.'}
|
||||
placeholder="Delimiter"
|
||||
description={t('repeat.delimiterDescription')}
|
||||
placeholder={t('repeat.delimiterPlaceholder')}
|
||||
value={values.delimiter}
|
||||
onOwnChange={(val) => updateField('delimiter', val)}
|
||||
type={'text'}
|
||||
@@ -98,15 +100,18 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
inputComponent={
|
||||
<ToolTextInput title={'Input text'} value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('repeat.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={'Repeated text'} value={result} />
|
||||
<ToolTextResult title={t('repeat.resultTitle')} value={result} />
|
||||
}
|
||||
toolInfo={{
|
||||
title: 'Repeat text',
|
||||
description:
|
||||
'This tool allows you to repeat a given text multiple times with an optional separator.'
|
||||
title: t('repeat.toolInfo.title'),
|
||||
description: t('repeat.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
|
||||
@@ -2,13 +2,16 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Repeat text',
|
||||
path: 'repeat',
|
||||
shortDescription: 'Repeat text multiple times',
|
||||
|
||||
icon: 'material-symbols-light:replay',
|
||||
description:
|
||||
'This tool allows you to repeat a given text multiple times with an optional separator.',
|
||||
|
||||
keywords: ['text', 'repeat'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:repeat.title',
|
||||
description: 'string:repeat.description',
|
||||
shortDescription: 'string:repeat.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import ToolExamples, {
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { FormikProps } from 'formik';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const initialValues = {
|
||||
multiLine: true,
|
||||
@@ -58,6 +59,7 @@ const exampleCards: CardExampleType<typeof initialValues>[] = [
|
||||
];
|
||||
|
||||
export default function Reverse({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -74,27 +76,27 @@ export default function Reverse({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Reversal options',
|
||||
title: t('reverse.reversalOptions'),
|
||||
component: [
|
||||
<CheckboxWithDesc
|
||||
key="multiLine"
|
||||
checked={values.multiLine}
|
||||
title="Process multi-line text"
|
||||
description="Each line will be reversed independently"
|
||||
title={t('reverse.processMultiLine')}
|
||||
description={t('reverse.processMultiLineDescription')}
|
||||
onChange={(val) => updateField('multiLine', val)}
|
||||
/>,
|
||||
<CheckboxWithDesc
|
||||
key="emptyItems"
|
||||
checked={values.emptyItems}
|
||||
title="Skip empty lines"
|
||||
description="Empty lines will be removed from the output"
|
||||
title={t('reverse.skipEmptyLines')}
|
||||
description={t('reverse.skipEmptyLinesDescription')}
|
||||
onChange={(val) => updateField('emptyItems', val)}
|
||||
/>,
|
||||
<CheckboxWithDesc
|
||||
key="trim"
|
||||
checked={values.trim}
|
||||
title="Trim whitespace"
|
||||
description="Remove leading and trailing whitespace from each line"
|
||||
title={t('reverse.trimWhitespace')}
|
||||
description={t('reverse.trimWhitespaceDescription')}
|
||||
onChange={(val) => updateField('trim', val)}
|
||||
/>
|
||||
]
|
||||
@@ -109,9 +111,15 @@ export default function Reverse({ title }: ToolComponentProps) {
|
||||
compute={computeExternal}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
|
||||
inputComponent={
|
||||
<ToolTextInput
|
||||
title={t('reverse.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={'Reversed text'} value={result} />
|
||||
<ToolTextResult title={t('reverse.resultTitle')} value={result} />
|
||||
}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
|
||||
@@ -2,13 +2,15 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Reverse',
|
||||
path: 'reverse',
|
||||
icon: 'material-symbols-light:swap-horiz',
|
||||
description:
|
||||
"World's simplest browser-based utility for reversing text. Input any text and get it instantly reversed, character by character. Perfect for creating mirror text, analyzing palindromes, or playing with text patterns. Preserves spaces and special characters while reversing.",
|
||||
shortDescription: 'Reverse any text character by character',
|
||||
|
||||
keywords: ['reverse'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:reverse.title',
|
||||
description: 'string:reverse.description',
|
||||
shortDescription: 'string:reverse.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { rot13 } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type InitialValuesType = Record<string, never>;
|
||||
|
||||
@@ -30,6 +31,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
];
|
||||
|
||||
export default function Rot13({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -41,15 +43,20 @@ export default function Rot13({ title }: ToolComponentProps) {
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Text" value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('rot13.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('rot13.resultTitle')} value={result} />
|
||||
}
|
||||
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.'
|
||||
title: t('rot13.toolInfo.title'),
|
||||
description: t('rot13.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
|
||||
@@ -3,12 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Rot13',
|
||||
i18n: {
|
||||
name: 'string:rot13.title',
|
||||
description: 'string:rot13.description',
|
||||
shortDescription: 'string:rot13.shortDescription'
|
||||
},
|
||||
|
||||
path: 'rot13',
|
||||
icon: 'hugeicons:encrypt',
|
||||
description:
|
||||
'A simple tool to encode or decode text using the ROT13 cipher, which replaces each letter with the letter 13 positions after it in the alphabet.',
|
||||
shortDescription: 'Encode or decode text using ROT13 cipher.',
|
||||
|
||||
keywords: ['rot13'],
|
||||
userTypes: ['Developers', 'CyberSec', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
|
||||
@@ -10,6 +10,7 @@ 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 { useTranslation } from 'react-i18next';
|
||||
|
||||
interface InitialValuesType {
|
||||
step: string;
|
||||
@@ -63,6 +64,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
];
|
||||
|
||||
export default function Rotate({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -79,29 +81,29 @@ export default function Rotate({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Rotation Options',
|
||||
title: t('rotate.rotationOptions'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.step}
|
||||
onOwnChange={(val) => updateField('step', val)}
|
||||
description={'Number of positions to rotate'}
|
||||
description={t('rotate.stepDescription')}
|
||||
type="number"
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('direction', 'right')}
|
||||
checked={values.direction === 'right'}
|
||||
title={'Rotate Right'}
|
||||
title={t('rotate.rotateRight')}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('direction', 'left')}
|
||||
checked={values.direction === 'left'}
|
||||
title={'Rotate Left'}
|
||||
title={t('rotate.rotateLeft')}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.multiLine}
|
||||
onChange={(checked) => updateField('multiLine', checked)}
|
||||
title={'Process as multi-line text (rotate each line separately)'}
|
||||
title={t('rotate.processAsMultiLine')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
@@ -112,15 +114,20 @@ export default function Rotate({ title }: ToolComponentProps) {
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={
|
||||
<ToolTextInput title="Input Text" value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('rotate.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('rotate.resultTitle')} value={result} />
|
||||
}
|
||||
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.'
|
||||
title: t('rotate.toolInfo.title'),
|
||||
description: t('rotate.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
input={input}
|
||||
|
||||
@@ -3,12 +3,15 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Rotate',
|
||||
i18n: {
|
||||
name: 'string:rotate.title',
|
||||
description: 'string:rotate.description',
|
||||
shortDescription: 'string:rotate.shortDescription'
|
||||
},
|
||||
|
||||
path: 'rotate',
|
||||
icon: 'carbon:rotate',
|
||||
description:
|
||||
'A tool to rotate characters in a string by a specified number of positions. Shift characters left or right while maintaining their relative order.',
|
||||
shortDescription: 'Shift characters in text by position.',
|
||||
|
||||
keywords: ['rotate'],
|
||||
userTypes: ['General Users', 'Students', 'Developers'],
|
||||
component: lazy(() => import('./index'))
|
||||
|
||||
@@ -11,6 +11,8 @@ import ToolExamples, {
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { FormikProps } from 'formik';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ParseKeys } from 'i18next';
|
||||
|
||||
const initialValues = {
|
||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||
@@ -24,55 +26,45 @@ const initialValues = {
|
||||
charAfterChunk: ''
|
||||
};
|
||||
const splitOperators: {
|
||||
title: string;
|
||||
description: string;
|
||||
title: ParseKeys<'string'>;
|
||||
description: ParseKeys<'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.)',
|
||||
title: 'split.symbolTitle',
|
||||
description: 'split.symbolDescription',
|
||||
type: 'symbol'
|
||||
},
|
||||
{
|
||||
title: 'Use a Regex for Splitting',
|
||||
title: 'split.regexTitle',
|
||||
type: 'regex',
|
||||
description:
|
||||
'Regular expression that will be\n' +
|
||||
'used to break text into parts.\n' +
|
||||
'(Multiple spaces by default.)'
|
||||
description: 'split.regexDescription'
|
||||
},
|
||||
{
|
||||
title: 'Use Length for Splitting',
|
||||
description:
|
||||
'Number of symbols that will be\n' + 'put in each output chunk.',
|
||||
title: 'split.lengthTitle',
|
||||
description: 'split.lengthDescription',
|
||||
type: 'length'
|
||||
},
|
||||
{
|
||||
title: 'Use a Number of Chunks',
|
||||
description: 'Number of chunks of equal\n' + 'length in the output.',
|
||||
title: 'split.chunksTitle',
|
||||
description: 'split.chunksDescription',
|
||||
type: 'chunks'
|
||||
}
|
||||
];
|
||||
const outputOptions: {
|
||||
description: string;
|
||||
description: ParseKeys<'string'>;
|
||||
accessor: keyof typeof initialValues;
|
||||
}[] = [
|
||||
{
|
||||
description:
|
||||
'Character that will be put\n' +
|
||||
'between the split chunks.\n' +
|
||||
'(It\'s newline "\\n" by default.)',
|
||||
description: 'split.outputSeparatorDescription',
|
||||
accessor: 'outputSeparator'
|
||||
},
|
||||
{
|
||||
description: 'Character before each chunk',
|
||||
description: 'split.charBeforeChunkDescription',
|
||||
accessor: 'charBeforeChunk'
|
||||
},
|
||||
{
|
||||
description: 'Character after each chunk',
|
||||
description: 'split.charAfterChunkDescription',
|
||||
accessor: 'charAfterChunk'
|
||||
}
|
||||
];
|
||||
@@ -132,6 +124,7 @@ easy`,
|
||||
];
|
||||
|
||||
export default function SplitText({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -170,18 +163,20 @@ export default function SplitText({ title }: ToolComponentProps) {
|
||||
title={title}
|
||||
input={input}
|
||||
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
|
||||
resultComponent={<ToolTextResult title={'Text pieces'} value={result} />}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('split.resultTitle')} value={result} />
|
||||
}
|
||||
initialValues={initialValues}
|
||||
getGroups={({ values, updateField }) => [
|
||||
{
|
||||
title: 'Split separator options',
|
||||
title: t('split.splitSeparatorOptions'),
|
||||
component: splitOperators.map(({ title, description, type }) => (
|
||||
<RadioWithTextField
|
||||
key={type}
|
||||
checked={type === values.splitSeparatorType}
|
||||
title={title}
|
||||
title={t(title)}
|
||||
fieldName={'splitSeparatorType'}
|
||||
description={description}
|
||||
description={t(description)}
|
||||
value={values[`${type}Value`]}
|
||||
onRadioClick={() => updateField('splitSeparatorType', type)}
|
||||
onTextChange={(val) => updateField(`${type}Value`, val)}
|
||||
@@ -189,13 +184,13 @@ export default function SplitText({ title }: ToolComponentProps) {
|
||||
))
|
||||
},
|
||||
{
|
||||
title: 'Output separator options',
|
||||
title: t('split.outputSeparatorOptions'),
|
||||
component: outputOptions.map((option) => (
|
||||
<TextFieldWithDesc
|
||||
key={option.accessor}
|
||||
value={values[option.accessor]}
|
||||
onOwnChange={(value) => updateField(option.accessor, value)}
|
||||
description={option.description}
|
||||
description={t(option.description)}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
@@ -3,13 +3,15 @@ import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
path: 'split',
|
||||
name: 'Text splitter',
|
||||
icon: 'material-symbols-light:arrow-split',
|
||||
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',
|
||||
longDescription: 'Quickly split a text',
|
||||
keywords: ['text', 'split'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
|
||||
icon: 'material-symbols-light:call-split',
|
||||
|
||||
keywords: ['split'],
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:split.title',
|
||||
description: 'string:split.description',
|
||||
shortDescription: 'string:split.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
emptyLines: false,
|
||||
@@ -216,6 +217,7 @@ export default function Truncate({
|
||||
title,
|
||||
longDescription
|
||||
}: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -228,49 +230,45 @@ export default function Truncate({
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Delimiters Options',
|
||||
title: t('statistic.delimitersOptions'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.sentenceDelimiters}
|
||||
onOwnChange={(val) => updateField('sentenceDelimiters', val)}
|
||||
placeholder="e.g. ., !, ?, ..."
|
||||
description={
|
||||
'Enter custom characters used to delimit sentences in your language (separated by comma) or leave it blank for default.'
|
||||
}
|
||||
placeholder={t('statistic.sentenceDelimitersPlaceholder')}
|
||||
description={t('statistic.sentenceDelimitersDescription')}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
value={values.wordDelimiters}
|
||||
onOwnChange={(val) => updateField('wordDelimiters', val)}
|
||||
placeholder="eg. \\s.,;:!?\”«»()…"
|
||||
description={
|
||||
'Enter custom Regex to count Words or leave it blank for default.'
|
||||
}
|
||||
placeholder={t('statistic.wordDelimitersPlaceholder')}
|
||||
description={t('statistic.wordDelimitersDescription')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Statistics Options',
|
||||
title: t('statistic.statisticsOptions'),
|
||||
component: (
|
||||
<Box>
|
||||
<CheckboxWithDesc
|
||||
checked={values.wordCount}
|
||||
onChange={(value) => updateField('wordCount', value)}
|
||||
title="Word Frequency Analysis"
|
||||
description="Count how often each word appears in the text"
|
||||
title={t('statistic.wordFrequencyAnalysis')}
|
||||
description={t('statistic.wordFrequencyAnalysisDescription')}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.characterCount}
|
||||
onChange={(value) => updateField('characterCount', value)}
|
||||
title="Character Frequency Analysis"
|
||||
description="Count how often each character appears in the text"
|
||||
title={t('statistic.characterFrequencyAnalysis')}
|
||||
description={t('statistic.characterFrequencyAnalysisDescription')}
|
||||
/>
|
||||
<CheckboxWithDesc
|
||||
checked={values.emptyLines}
|
||||
onChange={(value) => updateField('emptyLines', value)}
|
||||
title="Include Empty Lines"
|
||||
description="Include blank lines when counting lines"
|
||||
title={t('statistic.includeEmptyLines')}
|
||||
description={t('statistic.includeEmptyLinesDescription')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
@@ -286,12 +284,19 @@ export default function Truncate({
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
inputComponent={
|
||||
<ToolTextInput title={'Input text'} value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('statistic.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={'Text Statistics'} value={result} />
|
||||
<ToolTextResult title={t('statistic.resultTitle')} value={result} />
|
||||
}
|
||||
toolInfo={{ title: `What is a ${title}?`, description: longDescription }}
|
||||
toolInfo={{
|
||||
title: t('statistic.toolInfo.title', { title }),
|
||||
description: longDescription
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -2,15 +2,16 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Text Statistics',
|
||||
path: 'statistics',
|
||||
shortDescription: 'Get statistics about your text',
|
||||
|
||||
icon: 'fluent:document-landscape-data-24-filled',
|
||||
description:
|
||||
'Load your text in the input form on the left and you will automatically get statistics about your text on the right.',
|
||||
longDescription:
|
||||
'This tool provides various statistics about the text you input, including the number of lines, words, and characters. You can also choose to include empty lines in the count. it can count words and characters based on custom delimiters, allowing for flexible text analysis. Additionally, it can provide frequency statistics for words and characters, helping you understand the distribution of terms in your text.',
|
||||
|
||||
keywords: ['text', 'statistics', 'count', 'lines', 'words', 'characters'],
|
||||
userTypes: ['General Users', 'Students', 'Developers'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:statistic.title',
|
||||
description: 'string:statistic.description',
|
||||
shortDescription: 'string:statistic.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import { initialValues, InitialValuesType } from './initialValues';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
@@ -60,6 +61,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
];
|
||||
|
||||
export default function Replacer({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -72,16 +74,16 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Search text',
|
||||
title: t('textReplacer.searchText'),
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('mode', 'text')}
|
||||
checked={values.mode === 'text'}
|
||||
title={'Find This Pattern in Text'}
|
||||
title={t('textReplacer.findPatternInText')}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
description={'Enter the text pattern that you want to replace.'}
|
||||
description={t('textReplacer.searchPatternDescription')}
|
||||
value={values.searchValue}
|
||||
onOwnChange={(val) => updateField('searchValue', val)}
|
||||
type={'text'}
|
||||
@@ -89,12 +91,10 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('mode', 'regexp')}
|
||||
checked={values.mode === 'regexp'}
|
||||
title={'Find a Pattern Using a RegExp'}
|
||||
title={t('textReplacer.findPatternUsingRegexp')}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
description={
|
||||
'Enter the regular expression that you want to replace.'
|
||||
}
|
||||
description={t('textReplacer.regexpDescription')}
|
||||
value={values.searchRegexp}
|
||||
onOwnChange={(val) => updateField('searchRegexp', val)}
|
||||
type={'text'}
|
||||
@@ -103,12 +103,12 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Replace Text',
|
||||
title: t('textReplacer.replaceText'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
description={'Enter the pattern to use for replacement.'}
|
||||
placeholder={'New text'}
|
||||
description={t('textReplacer.replacePatternDescription')}
|
||||
placeholder={t('textReplacer.newTextPlaceholder')}
|
||||
value={values.replaceValue}
|
||||
onOwnChange={(val) => updateField('replaceValue', val)}
|
||||
type={'text'}
|
||||
@@ -128,18 +128,17 @@ export default function Replacer({ title }: ToolComponentProps) {
|
||||
setInput={setInput}
|
||||
inputComponent={
|
||||
<ToolTextInput
|
||||
title="Text to replace"
|
||||
title={t('textReplacer.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={'Text with replacements'} value={result} />
|
||||
<ToolTextResult title={t('textReplacer.resultTitle')} value={result} />
|
||||
}
|
||||
toolInfo={{
|
||||
title: 'Text Replacer',
|
||||
description:
|
||||
'Easily replace specific text in your content with this simple, browser-based tool. Just input your text, set the text you want to replace and the replacement value, and instantly get the updated version.'
|
||||
title: t('textReplacer.toolInfo.title'),
|
||||
description: t('textReplacer.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
|
||||
@@ -2,12 +2,16 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Text Replacer',
|
||||
i18n: {
|
||||
name: 'string:textReplacer.title',
|
||||
description: 'string:textReplacer.description',
|
||||
shortDescription: 'string:textReplacer.shortDescription'
|
||||
},
|
||||
|
||||
path: 'replacer',
|
||||
shortDescription: 'Quickly replace text in your content',
|
||||
|
||||
icon: 'material-symbols-light:find-replace',
|
||||
description:
|
||||
'Easily replace specific text in your content with this simple, browser-based tool. Just input your text, set the text you want to replace and the replacement value, and instantly get the updated version.',
|
||||
|
||||
keywords: ['text', 'replace'],
|
||||
userTypes: ['General Users', 'Students', 'Developers'],
|
||||
component: lazy(() => import('./index'))
|
||||
|
||||
@@ -4,6 +4,7 @@ import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { compute } from './service';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const initialValues = {
|
||||
dotSymbol: '.',
|
||||
@@ -11,6 +12,7 @@ const initialValues = {
|
||||
};
|
||||
|
||||
export default function ToMorse() {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
const computeOptions = (optionsValues: typeof initialValues, input: any) => {
|
||||
@@ -20,33 +22,31 @@ export default function ToMorse() {
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title="To Morse"
|
||||
title={t('toMorse.title')}
|
||||
initialValues={initialValues}
|
||||
compute={computeOptions}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
|
||||
resultComponent={<ToolTextResult title={'Morse code'} value={result} />}
|
||||
resultComponent={
|
||||
<ToolTextResult title={t('toMorse.resultTitle')} value={result} />
|
||||
}
|
||||
getGroups={({ values, updateField }) => [
|
||||
{
|
||||
title: 'Short Signal',
|
||||
title: t('toMorse.shortSignal'),
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
description={
|
||||
'Symbol that will correspond to the dot in Morse code.'
|
||||
}
|
||||
description={t('toMorse.dotSymbolDescription')}
|
||||
value={values.dotSymbol}
|
||||
onOwnChange={(val) => updateField('dotSymbol', val)}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Long Signal',
|
||||
title: t('toMorse.longSignal'),
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
description={
|
||||
'Symbol that will correspond to the dash in Morse code.'
|
||||
}
|
||||
description={t('toMorse.dashSymbolDescription')}
|
||||
value={values.dashSymbol}
|
||||
onOwnChange={(val) => updateField('dashSymbol', val)}
|
||||
/>
|
||||
|
||||
@@ -3,13 +3,14 @@ import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'String To morse',
|
||||
path: 'to-morse',
|
||||
icon: 'arcticons:morse',
|
||||
description:
|
||||
"World's simplest browser-based utility for converting text to Morse code. Load your text in the input form on the left and you'll instantly get Morse code in the output area. Powerful, free, and fast. Load text – get Morse code.",
|
||||
shortDescription: 'Quickly encode text to morse',
|
||||
keywords: ['to', 'morse'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:toMorse.title',
|
||||
description: 'string:toMorse.description',
|
||||
shortDescription: 'string:toMorse.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import SimpleRadio from '@components/options/SimpleRadio';
|
||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
@@ -67,6 +68,7 @@ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
|
||||
];
|
||||
|
||||
export default function Truncate({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -79,31 +81,31 @@ export default function Truncate({ title }: ToolComponentProps) {
|
||||
updateField
|
||||
}) => [
|
||||
{
|
||||
title: 'Truncation Side',
|
||||
title: t('truncate.truncationSide'),
|
||||
component: (
|
||||
<Box>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('truncationSide', 'right')}
|
||||
checked={values.truncationSide === 'right'}
|
||||
title={'Right-side Truncation'}
|
||||
description={'Remove characters from the end of the text.'}
|
||||
title={t('truncate.rightSideTruncation')}
|
||||
description={t('truncate.rightSideDescription')}
|
||||
/>
|
||||
<SimpleRadio
|
||||
onClick={() => updateField('truncationSide', 'left')}
|
||||
checked={values.truncationSide === 'left'}
|
||||
title={'Left-side Truncation'}
|
||||
description={'Remove characters from the start of the text.'}
|
||||
title={t('truncate.leftSideTruncation')}
|
||||
description={t('truncate.leftSideDescription')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Length and Lines',
|
||||
title: t('truncate.lengthAndLines'),
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
description={'Number of characters to leave in the text.'}
|
||||
placeholder="Number"
|
||||
description={t('truncate.maxLengthDescription')}
|
||||
placeholder={t('truncate.numberPlaceholder')}
|
||||
value={values.maxLength}
|
||||
onOwnChange={(val) => updateField('maxLength', val)}
|
||||
type={'number'}
|
||||
@@ -111,27 +113,25 @@ export default function Truncate({ title }: ToolComponentProps) {
|
||||
<CheckboxWithDesc
|
||||
onChange={(val) => updateField('lineByLine', val)}
|
||||
checked={values.lineByLine}
|
||||
title={'Line-by-line Truncating'}
|
||||
description={'Truncate each line separately.'}
|
||||
title={t('truncate.lineByLineTruncating')}
|
||||
description={t('truncate.lineByLineDescription')}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Suffix and Affix',
|
||||
title: t('truncate.suffixAndAffix'),
|
||||
component: (
|
||||
<Box>
|
||||
<CheckboxWithDesc
|
||||
onChange={(val) => updateField('addIndicator', val)}
|
||||
checked={values.addIndicator}
|
||||
title={'Add Truncation Indicator'}
|
||||
title={t('truncate.addTruncationIndicator')}
|
||||
description={''}
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
description={
|
||||
'Characters to add at the end (or start) of the text. Note: They count towards the length.'
|
||||
}
|
||||
placeholder="Characters"
|
||||
description={t('truncate.indicatorDescription')}
|
||||
placeholder={t('truncate.charactersPlaceholder')}
|
||||
value={values.indicator}
|
||||
onOwnChange={(val) => updateField('indicator', val)}
|
||||
type={'text'}
|
||||
@@ -150,15 +150,18 @@ export default function Truncate({ title }: ToolComponentProps) {
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
inputComponent={
|
||||
<ToolTextInput title={'Input text'} value={input} onChange={setInput} />
|
||||
<ToolTextInput
|
||||
title={t('truncate.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={'Truncated text'} value={result} />
|
||||
<ToolTextResult title={t('truncate.resultTitle')} value={result} />
|
||||
}
|
||||
toolInfo={{
|
||||
title: 'Truncate text',
|
||||
description:
|
||||
'Load your text in the input form on the left and you will automatically get truncated text on the right.'
|
||||
title: t('truncate.toolInfo.title'),
|
||||
description: t('truncate.toolInfo.description')
|
||||
}}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
|
||||
@@ -2,13 +2,15 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Truncate text',
|
||||
path: 'truncate',
|
||||
shortDescription: 'Truncate your text easily',
|
||||
icon: 'material-symbols-light:short-text',
|
||||
description:
|
||||
'Load your text in the input form on the left and you will automatically get truncated text on the right.',
|
||||
keywords: ['text', 'truncate'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
icon: 'material-symbols-light:content-cut',
|
||||
|
||||
keywords: ['truncate'],
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:truncate.title',
|
||||
description: 'string:truncate.description',
|
||||
shortDescription: 'string:truncate.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { UppercaseInput } from './service';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const initialValues = {};
|
||||
|
||||
@@ -35,6 +36,7 @@ const exampleCards: CardExampleType<typeof initialValues>[] = [
|
||||
];
|
||||
|
||||
export default function Uppercase({ title }: ToolComponentProps) {
|
||||
const { t } = useTranslation('string');
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
@@ -53,9 +55,15 @@ export default function Uppercase({ title }: ToolComponentProps) {
|
||||
compute={computeExternal}
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
|
||||
inputComponent={
|
||||
<ToolTextInput
|
||||
title={t('uppercase.inputTitle')}
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ToolTextResult title={'Uppercase text'} value={result} />
|
||||
<ToolTextResult title={t('uppercase.resultTitle')} value={result} />
|
||||
}
|
||||
exampleCards={exampleCards}
|
||||
/>
|
||||
|
||||
@@ -2,13 +2,15 @@ import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('string', {
|
||||
name: 'Uppercase',
|
||||
path: 'uppercase',
|
||||
icon: 'material-symbols-light:text-fields',
|
||||
description:
|
||||
"World's simplest browser-based utility for converting text to uppercase. Just input your text and it will be automatically converted to all capital letters. Perfect for creating headlines, emphasizing text, or standardizing text format. Supports various text formats and preserves special characters.",
|
||||
shortDescription: 'Convert text to uppercase letters',
|
||||
icon: 'material-symbols-light:format-textdirection-l-to-r',
|
||||
|
||||
keywords: ['uppercase'],
|
||||
userTypes: ['General Users', 'Students'],
|
||||
component: lazy(() => import('./index'))
|
||||
component: lazy(() => import('./index')),
|
||||
i18n: {
|
||||
name: 'string:uppercase.title',
|
||||
description: 'string:uppercase.description',
|
||||
shortDescription: 'string:uppercase.shortDescription',
|
||||
userTypes: ['General Users', 'Students', 'Developers']
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user