Skip to content

Commit

Permalink
adding text joiner
Browse files Browse the repository at this point in the history
  • Loading branch information
Made4Uo committed Jun 23, 2024
1 parent 3ca1b7c commit cbb7790
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"trailingComma": "none",
"singleQuote": true
"singleQuote": true,
"endOfLine": "auto"
}
2 changes: 1 addition & 1 deletion src/components/input/ToolTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function ToolTextInput({
.writeText(value)
.then(() => showSnackBar('Text copied', 'success'))
.catch((err) => {
showSnackBar('Failed to copy: ', 'error');
showSnackBar('Failed to copy: ', err);
});
};
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
Expand Down
181 changes: 181 additions & 0 deletions src/pages/string/join/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import {
Box,
Checkbox,
FormControlLabel,
Grid,
Stack,
TextField,
Typography
} from '@mui/material';
import React, { useContext, useEffect, useRef, useState } from 'react';
import { Formik, FormikProps, useFormikContext } from 'formik';
import * as Yup from 'yup';
import ToolTextInput from '../../../components/input/ToolTextInput';
import ToolTextResult from '../../../components/result/ToolTextResult';
import ToolOptions from '../../../components/ToolOptions';
import { mergeText } from './service';
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';

const initialValues = {
joinCharacter: ' ',
deleteBlank: true,
deleteTrailing: true
};

const validationSchema = Yup.object().shape({
joinCharacter: Yup.string().required('Join character is required'),
deleteBlank: Yup.boolean().required('Delete blank is required'),
deleteTrailing: Yup.boolean().required('Delete trailing is required')
});

const mergeOptions = {
description:
'Symbol that connects broken\n' + 'pieces of text. (Space by default.)\n',
accessor: 'joinCharacter' as keyof typeof initialValues
};

const blankTrailingOptions: {
title: string;
description: string;
accessor: keyof typeof initialValues;
}[] = [
{
title: 'Delete Blank Lines',
description: "Delete lines that don't have\n" + 'text symbols.\n',
accessor: 'deleteBlank'
},
{
title: 'Delete Trailing Spaces',
description: 'Remove spaces and tabs at\n' + 'the end of the lines.\n',
accessor: 'deleteTrailing'
}
];

const InputWithDesc = ({
description,
value,
onChange
}: {
description: string;
value: string;
onChange: (value: string) => void;
}) => {
return (
<Box>
<TextField
sx={{ backgroundColor: 'white' }}
value={value}
onChange={(event) => onChange(event.target.value)}
/>
<Typography fontSize={12} mt={1}>
{description}
</Typography>
</Box>
);
};

const CheckboxWithDesc = ({
title,
description,
checked,
onChange
}: {
title: string;
description: string;
checked: boolean;
onChange: (value: boolean) => void;
}) => {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onChange(event.target.checked);
};

return (
<Box>
<FormControlLabel
control={
<Checkbox defaultChecked checked={checked} onChange={handleChange} />
}
label={title}
/>
<Typography fontSize={12} mt={1}>
{description}
</Typography>
</Box>
);
};

export default function JoinText() {
const [input, setInput] = useState<string>('');
const formRef = useRef<FormikProps<typeof initialValues>>(null);
const { showSnackBar } = useContext(CustomSnackBarContext);
const [result, setResult] = useState<string>('');

const FormikListenerComponent = ({ input }: { input: string }) => {
const { values } = useFormikContext<typeof initialValues>();
const { joinCharacter, deleteBlank, deleteTrailing } = values;

useEffect(() => {
try {
setResult(mergeText(input, deleteBlank, deleteTrailing, joinCharacter));
} catch (exception: unknown) {
if (exception instanceof Error)
showSnackBar(exception.message, 'error');
}
}, [values, input]);

return null;
};

return (
<Box>
<Grid container spacing={2}>
<Grid item xs={6}>
<ToolTextInput
title={'Text Pieces'}
value={input}
onChange={setInput}
/>
</Grid>
<Grid item xs={6}>
<ToolTextResult title={'Joined Text'} value={result} />
</Grid>
</Grid>
<ToolOptions>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
innerRef={formRef}
onSubmit={() => {}}
>
{({ setFieldValue, values }) => (
<Stack direction={'row'} spacing={2}>
<FormikListenerComponent input={input} />
<Box>
<Typography fontSize={22}>Text Merged Options</Typography>
<InputWithDesc
value={values.joinCharacter}
onChange={(value) => setFieldValue('joinCharacter', value)}
description={mergeOptions.description}
/>
</Box>
<Box>
<Typography fontSize={22}>
Blank Lines and Trailing Spaces
</Typography>
{blankTrailingOptions.map((option) => (
<CheckboxWithDesc
key={option.accessor}
title={option.title}
checked={!!values[option.accessor]}
onChange={(value) => setFieldValue(option.accessor, value)}
description={option.description}
/>
))}
</Box>
</Stack>
)}
</Formik>
</ToolOptions>
</Box>
);
}
13 changes: 13 additions & 0 deletions src/pages/string/join/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineTool } from '../../../tools/defineTool';
import { lazy } from 'react';
import image from '../../../assets/text.png';

export const tool = defineTool('string', {
path: 'join',
name: 'Text Joiner',
image,
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",
keywords: ['text', 'join'],
component: lazy(() => import('./index'))
});
29 changes: 29 additions & 0 deletions src/pages/string/join/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export function mergeText(
text: string,
deleteBlankLines: boolean = true,
deleteTrailingSpaces: boolean = true,
joinCharacter: string = ''
): string {
const lines = text.split('\n');

const processedLines = lines
.map((line) =>
deleteTrailingSpaces ? line.replace(/ |\r\n|\n|\r/gm, '') : line
)
.filter((line) => !deleteBlankLines || line.trim() !== '');

// Join lines and remove spaces right after each line
return processedLines.join(joinCharacter);
}

// Example usage
const text: string = `This is a line with trailing spaces
Another line with trailing spaces
Final line without trailing spaces`;

export const mergedTextWithBlankLines: string = mergeText(text, false);
console.log('With blank lines:\n', mergedTextWithBlankLines);

export const mergedTextWithoutBlankLines: string = mergeText(text, true);
console.log('Without blank lines:\n', mergedTextWithoutBlankLines);
3 changes: 2 additions & 1 deletion src/pages/string/stringTools.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { tool as stringSplit } from './split/meta';
import { tool as stringJoin } from './join/meta';

export const stringTools = [stringSplit];
export const stringTools = [stringSplit, stringJoin];

0 comments on commit cbb7790

Please sign in to comment.