mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-26 01:19:33 +02:00
feat: sum numbers init
This commit is contained in:
@@ -26,7 +26,7 @@ const exampleTools: { label: string; url: string }[] = [
|
||||
{ label: 'Find and replace text', url: '' },
|
||||
{ label: 'Convert emoji to image', url: '' },
|
||||
{ label: 'Split a string', url: '/string/split' },
|
||||
{ label: 'Calculate number sum', url: '' },
|
||||
{ label: 'Calculate number sum', url: '/number/sum' },
|
||||
{ label: 'Pixelate an image', url: '' }
|
||||
];
|
||||
export default function Home() {
|
||||
|
3
src/pages/number/index.ts
Normal file
3
src/pages/number/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { tool as numberSum } from './sum/meta';
|
||||
|
||||
export const numberTools = [numberSum];
|
157
src/pages/number/sum/index.tsx
Normal file
157
src/pages/number/sum/index.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
import { Box, Stack } from '@mui/material';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import ToolTextInput from '../../../components/input/ToolTextInput';
|
||||
import ToolTextResult from '../../../components/result/ToolTextResult';
|
||||
import { Formik, useFormikContext } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import ToolOptions from '../../../components/options/ToolOptions';
|
||||
import { compute, NumberExtractionType } from './service';
|
||||
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';
|
||||
import RadioWithTextField from '../../../components/options/RadioWithTextField';
|
||||
import ToolOptionGroups from '../../../components/options/ToolOptionGroups';
|
||||
import SimpleRadio from '../../../components/options/SimpleRadio';
|
||||
import CheckboxWithDesc from '../../../components/options/CheckboxWithDesc';
|
||||
|
||||
const initialValues = {
|
||||
extractionType: 'smart' as NumberExtractionType,
|
||||
separator: '\\n',
|
||||
printRunningSum: false
|
||||
};
|
||||
const extractionTypes: {
|
||||
title: string;
|
||||
description: string;
|
||||
type: NumberExtractionType;
|
||||
withTextField: boolean;
|
||||
textValueAccessor?: keyof typeof initialValues;
|
||||
}[] = [
|
||||
{
|
||||
title: 'Smart sum',
|
||||
description: 'Auto detect numbers in the input.',
|
||||
type: 'smart',
|
||||
withTextField: false
|
||||
},
|
||||
{
|
||||
title: 'Number Delimiter',
|
||||
type: 'delimiter',
|
||||
description:
|
||||
'Input SeparatorCustomize the number separator here. (By default a line break.)',
|
||||
withTextField: true,
|
||||
textValueAccessor: 'separator'
|
||||
}
|
||||
];
|
||||
|
||||
export default function SplitText() {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
// const formRef = useRef<FormikProps<typeof initialValues>>(null);
|
||||
const { showSnackBar } = useContext(CustomSnackBarContext);
|
||||
|
||||
const FormikListenerComponent = () => {
|
||||
const { values } = useFormikContext<typeof initialValues>();
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const { extractionType, printRunningSum, separator } = values;
|
||||
|
||||
setResult(compute(input, extractionType, printRunningSum, separator));
|
||||
} catch (exception: unknown) {
|
||||
if (exception instanceof Error)
|
||||
showSnackBar(exception.message, 'error');
|
||||
}
|
||||
}, [values, input]);
|
||||
|
||||
return null; // This component doesn't render anything
|
||||
};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<ToolTextInput value={input} onChange={setInput} />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<ToolTextResult title={'Text pieces'} value={result} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<ToolOptions>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={() => {}}
|
||||
>
|
||||
{({ setFieldValue, values }) => (
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<FormikListenerComponent />
|
||||
<ToolOptionGroups
|
||||
groups={[
|
||||
{
|
||||
title: 'Number extraction',
|
||||
component: extractionTypes.map(
|
||||
({
|
||||
title,
|
||||
description,
|
||||
type,
|
||||
withTextField,
|
||||
textValueAccessor
|
||||
}) =>
|
||||
withTextField ? (
|
||||
<RadioWithTextField
|
||||
key={type}
|
||||
radioValue={type}
|
||||
title={title}
|
||||
fieldName={'extractionType'}
|
||||
description={description}
|
||||
value={
|
||||
textValueAccessor
|
||||
? values[textValueAccessor].toString()
|
||||
: ''
|
||||
}
|
||||
onRadioChange={(type) =>
|
||||
setFieldValue('extractionType', type)
|
||||
}
|
||||
onTextChange={(val) =>
|
||||
setFieldValue(textValueAccessor ?? '', val)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<SimpleRadio
|
||||
key={title}
|
||||
onChange={() =>
|
||||
setFieldValue('extractionType', type)
|
||||
}
|
||||
fieldName={'extractionType'}
|
||||
value={values.extractionType}
|
||||
description={description}
|
||||
title={title}
|
||||
/>
|
||||
)
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Running Sum',
|
||||
component: (
|
||||
<CheckboxWithDesc
|
||||
title={'Print Running Sum'}
|
||||
description={
|
||||
"Display the sum as it's calculated step by step."
|
||||
}
|
||||
checked={values.printRunningSum}
|
||||
onChange={(value) =>
|
||||
setFieldValue('printRunningSum', value)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</Formik>
|
||||
</ToolOptions>
|
||||
</Box>
|
||||
);
|
||||
}
|
13
src/pages/number/sum/meta.ts
Normal file
13
src/pages/number/sum/meta.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('number', {
|
||||
name: 'Number Sum Calculator',
|
||||
path: 'sum',
|
||||
// image,
|
||||
description:
|
||||
'Quickly calculate the sum of numbers in your browser. To get your sum, just enter your list of numbers in the input field, adjust the separator between the numbers in the options below, and this utility will add up all these numbers.',
|
||||
keywords: ['sum'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
29
src/pages/number/sum/service.ts
Normal file
29
src/pages/number/sum/service.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export type NumberExtractionType = 'smart' | 'delimiter';
|
||||
|
||||
function getAllNumbers(text: string): number[] {
|
||||
const regex = /\d+/g;
|
||||
const matches = text.match(regex);
|
||||
return matches ? matches.map(Number) : [];
|
||||
}
|
||||
|
||||
export const compute = (
|
||||
input: string,
|
||||
extractionType: NumberExtractionType,
|
||||
printRunningSum: boolean,
|
||||
separator: string
|
||||
) => {
|
||||
let numbers: number[] = [];
|
||||
if (extractionType === 'smart') {
|
||||
numbers = getAllNumbers(input);
|
||||
} else {
|
||||
const parts = input.split(separator);
|
||||
// Filter out and convert parts that are numbers
|
||||
numbers = parts
|
||||
.filter((part) => !isNaN(Number(part)) && part.trim() !== '')
|
||||
.map(Number);
|
||||
}
|
||||
return numbers.reduce(
|
||||
(previousValue, currentValue) => previousValue + currentValue,
|
||||
0
|
||||
);
|
||||
};
|
6
src/pages/number/sum/sum.service.test.ts
Normal file
6
src/pages/number/sum/sum.service.test.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { expect, describe, it } from 'vitest';
|
||||
// import { } from './service';
|
||||
//
|
||||
// describe('sum', () => {
|
||||
//
|
||||
// })
|
@@ -151,12 +151,12 @@ export default function SplitText() {
|
||||
({ title, description, type }) => (
|
||||
<RadioWithTextField
|
||||
key={type}
|
||||
type={type}
|
||||
radioValue={type}
|
||||
title={title}
|
||||
fieldName={'splitSeparatorType'}
|
||||
description={description}
|
||||
value={values[`${type}Value`]}
|
||||
onTypeChange={(type) =>
|
||||
onRadioChange={(type) =>
|
||||
setFieldValue('splitSeparatorType', type)
|
||||
}
|
||||
onTextChange={(val) =>
|
||||
|
@@ -6,7 +6,8 @@ export const tool = defineTool('string', {
|
||||
name: 'String To morse',
|
||||
path: 'to-morse',
|
||||
// image,
|
||||
description: '',
|
||||
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.",
|
||||
keywords: ['to', 'morse'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
Reference in New Issue
Block a user