diff --git a/.prettierrc b/.prettierrc index e9c0f50..313a51f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "trailingComma": "none", - "singleQuote": true + "singleQuote": true, + "endOfLine": "auto" } diff --git a/src/components/input/ToolTextInput.tsx b/src/components/input/ToolTextInput.tsx index 3d27244..ff98536 100644 --- a/src/components/input/ToolTextInput.tsx +++ b/src/components/input/ToolTextInput.tsx @@ -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) => { diff --git a/src/pages/string/join/index.tsx b/src/pages/string/join/index.tsx new file mode 100644 index 0000000..d7bc4e9 --- /dev/null +++ b/src/pages/string/join/index.tsx @@ -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 ( + + onChange(event.target.value)} + /> + + {description} + + + ); +}; + +const CheckboxWithDesc = ({ + title, + description, + checked, + onChange +}: { + title: string; + description: string; + checked: boolean; + onChange: (value: boolean) => void; +}) => { + const handleChange = (event: React.ChangeEvent) => { + onChange(event.target.checked); + }; + + return ( + + + } + label={title} + /> + + {description} + + + ); +}; + +export default function JoinText() { + const [input, setInput] = useState(''); + const formRef = useRef>(null); + const { showSnackBar } = useContext(CustomSnackBarContext); + const [result, setResult] = useState(''); + + const FormikListenerComponent = ({ input }: { input: string }) => { + const { values } = useFormikContext(); + 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 ( + + + + + + + + + + + {}} + > + {({ setFieldValue, values }) => ( + + + + Text Merged Options + setFieldValue('joinCharacter', value)} + description={mergeOptions.description} + /> + + + + Blank Lines and Trailing Spaces + + {blankTrailingOptions.map((option) => ( + setFieldValue(option.accessor, value)} + description={option.description} + /> + ))} + + + )} + + + + ); +} diff --git a/src/pages/string/join/meta.ts b/src/pages/string/join/meta.ts new file mode 100644 index 0000000..1984a32 --- /dev/null +++ b/src/pages/string/join/meta.ts @@ -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')) +}); diff --git a/src/pages/string/join/service.ts b/src/pages/string/join/service.ts new file mode 100644 index 0000000..91d96d4 --- /dev/null +++ b/src/pages/string/join/service.ts @@ -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); diff --git a/src/pages/string/stringTools.ts b/src/pages/string/stringTools.ts index a89fc70..b53d52c 100644 --- a/src/pages/string/stringTools.ts +++ b/src/pages/string/stringTools.ts @@ -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];