mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-19 05:59:34 +02:00
feat: arithmetic sequence
This commit is contained in:
3
.codebuddy/.gitignore
vendored
3
.codebuddy/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
db/
|
||||
db/
|
||||
docs
|
||||
|
44
.idea/workspace.xml
generated
44
.idea/workspace.xml
generated
@@ -4,17 +4,21 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: minify json">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: stringify json">
|
||||
<change afterPath="$PROJECT_DIR$/.codebuddy/docs/Generate an Arithmetic Progression - Online Number Tools.txt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.codebuddy/docs/Stringify JSON - Online JSON Tools.txt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/json/stringify/index.tsx" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/json/stringify/meta.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/json/stringify/service.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/number/arithmetic-sequence/arithmetic-sequence.service.test.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/number/arithmetic-sequence/index.tsx" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/number/arithmetic-sequence/meta.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/pages/tools/number/arithmetic-sequence/service.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.codebuddy/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.codebuddy/.gitignore" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/index.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/minify/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/minify/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/prettify/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/prettify/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/utils/string.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/string.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tsconfig.json" beforeDir="false" afterPath="$PROJECT_DIR$/tsconfig.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/ToolContent.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolContent.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/examples/ExampleCard.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/examples/ExampleCard.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/examples/ToolExamples.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/examples/ToolExamples.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/json/stringify/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/json/stringify/meta.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/index.ts" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -337,14 +341,6 @@
|
||||
<workItem from="1740923024259" duration="23000" />
|
||||
<workItem from="1740933006573" duration="3679000" />
|
||||
</task>
|
||||
<task id="LOCAL-00095" summary="feat: self host">
|
||||
<option name="closed" value="true" />
|
||||
<created>1720665220407</created>
|
||||
<option name="number" value="00095" />
|
||||
<option name="presentableId" value="LOCAL-00095" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1720665220408</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00096" summary="chore: format number">
|
||||
<option name="closed" value="true" />
|
||||
<created>1720730102816</created>
|
||||
@@ -729,7 +725,15 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1741416193639</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="144" />
|
||||
<task id="LOCAL-00144" summary="feat: stringify json">
|
||||
<option name="closed" value="true" />
|
||||
<created>1741417920442</created>
|
||||
<option name="number" value="00144" />
|
||||
<option name="presentableId" value="LOCAL-00144" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1741417920442</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="145" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -788,7 +792,6 @@
|
||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
||||
<option name="CHECK_NEW_TODO" value="false" />
|
||||
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
|
||||
<MESSAGE value="fix: readme" />
|
||||
<MESSAGE value="fix: broken links" />
|
||||
<MESSAGE value="chore: style buttons" />
|
||||
<MESSAGE value="chore: style" />
|
||||
@@ -813,7 +816,8 @@
|
||||
<MESSAGE value="fix: replace text service" />
|
||||
<MESSAGE value="chore: smooth scroll for use this tool and examles" />
|
||||
<MESSAGE value="feat: minify json" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat: minify json" />
|
||||
<MESSAGE value="feat: stringify json" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat: stringify json" />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
|
@@ -10,7 +10,7 @@ import ToolExamples, {
|
||||
} from '@components/examples/ToolExamples';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
|
||||
interface ToolContentPropsBase<T, I> extends ToolComponentProps {
|
||||
interface ToolContentProps<T, I> extends ToolComponentProps {
|
||||
// Input/Output components
|
||||
inputComponent: ReactNode;
|
||||
resultComponent: ReactNode;
|
||||
@@ -29,28 +29,15 @@ interface ToolContentPropsBase<T, I> extends ToolComponentProps {
|
||||
};
|
||||
|
||||
// Input value to pass to the compute function
|
||||
input: I;
|
||||
input?: I;
|
||||
|
||||
exampleCards?: CardExampleType<T>[];
|
||||
setInput?: React.Dispatch<React.SetStateAction<I>>;
|
||||
|
||||
// Validation schema (optional)
|
||||
validationSchema?: any;
|
||||
}
|
||||
|
||||
interface ToolContentPropsWithExamples<T, I>
|
||||
extends ToolContentPropsBase<T, I> {
|
||||
exampleCards: CardExampleType<T>[];
|
||||
setInput: React.Dispatch<React.SetStateAction<I>>;
|
||||
}
|
||||
|
||||
interface ToolContentPropsWithoutExamples<T, I>
|
||||
extends ToolContentPropsBase<T, I> {
|
||||
exampleCards?: never;
|
||||
setInput?: never;
|
||||
}
|
||||
|
||||
type ToolContentProps<T, I> =
|
||||
| ToolContentPropsWithExamples<T, I>
|
||||
| ToolContentPropsWithoutExamples<T, I>;
|
||||
|
||||
export default function ToolContent<T extends FormikValues, I>({
|
||||
title,
|
||||
inputComponent,
|
||||
|
@@ -14,10 +14,10 @@ import { GetGroupsType } from '@components/options/ToolOptions';
|
||||
export interface ExampleCardProps<T> {
|
||||
title: string;
|
||||
description: string;
|
||||
sampleText: string;
|
||||
sampleText?: string;
|
||||
sampleResult: string;
|
||||
sampleOptions: T;
|
||||
changeInputResult: (newInput: string, newOptions: T) => void;
|
||||
changeInputResult: (newInput: string | undefined, newOptions: T) => void;
|
||||
getGroups: GetGroupsType<T> | null;
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@ export interface ExampleProps<T> {
|
||||
exampleCards: CardExampleType<T>[];
|
||||
getGroups: GetGroupsType<T> | null;
|
||||
formRef: React.RefObject<FormikProps<T>>;
|
||||
setInput: React.Dispatch<React.SetStateAction<any>>;
|
||||
setInput?: React.Dispatch<React.SetStateAction<any>>;
|
||||
}
|
||||
|
||||
export default function ToolExamples<T>({
|
||||
@@ -26,8 +26,8 @@ export default function ToolExamples<T>({
|
||||
formRef,
|
||||
setInput
|
||||
}: ExampleProps<T>) {
|
||||
function changeInputResult(newInput: string, newOptions: T) {
|
||||
setInput(newInput);
|
||||
function changeInputResult(newInput: string | undefined, newOptions: T) {
|
||||
setInput?.(newInput);
|
||||
formRef.current?.setValues(newOptions);
|
||||
const toolsElement = document.getElementById('tool');
|
||||
if (toolsElement) {
|
||||
|
@@ -4,9 +4,18 @@ import { lazy } from 'react';
|
||||
export const tool = defineTool('json', {
|
||||
name: 'Stringify JSON',
|
||||
path: 'stringify',
|
||||
icon: 'lets-icons:json-format-light',
|
||||
description: 'Convert JavaScript objects and arrays into their JSON string representation. Options include custom indentation and HTML character escaping for web-safe JSON strings.',
|
||||
icon: 'ant-design:field-string-outlined',
|
||||
description:
|
||||
'Convert JavaScript objects and arrays into their JSON string representation. Options include custom indentation and HTML character escaping for web-safe JSON strings.',
|
||||
shortDescription: 'Convert JavaScript objects to JSON strings',
|
||||
keywords: ['stringify', 'serialize', 'convert', 'object', 'array', 'json', 'string'],
|
||||
keywords: [
|
||||
'stringify',
|
||||
'serialize',
|
||||
'convert',
|
||||
'object',
|
||||
'array',
|
||||
'json',
|
||||
'string'
|
||||
],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { generateArithmeticSequence } from './service';
|
||||
|
||||
describe('generateArithmeticSequence', () => {
|
||||
it('should generate basic arithmetic sequence', () => {
|
||||
const result = generateArithmeticSequence(1, 2, 5, ', ');
|
||||
expect(result).toBe('1, 3, 5, 7, 9');
|
||||
});
|
||||
|
||||
it('should handle negative first term', () => {
|
||||
const result = generateArithmeticSequence(-5, 2, 5, ' ');
|
||||
expect(result).toBe('-5 -3 -1 1 3');
|
||||
});
|
||||
|
||||
it('should handle negative common difference', () => {
|
||||
const result = generateArithmeticSequence(10, -2, 5, ',');
|
||||
expect(result).toBe('10,8,6,4,2');
|
||||
});
|
||||
|
||||
it('should handle decimal numbers', () => {
|
||||
const result = generateArithmeticSequence(1.5, 0.5, 4, ' ');
|
||||
expect(result).toBe('1.5 2 2.5 3');
|
||||
});
|
||||
|
||||
it('should handle single term sequence', () => {
|
||||
const result = generateArithmeticSequence(1, 2, 1, ',');
|
||||
expect(result).toBe('1');
|
||||
});
|
||||
});
|
136
src/pages/tools/number/arithmetic-sequence/index.tsx
Normal file
136
src/pages/tools/number/arithmetic-sequence/index.tsx
Normal file
@@ -0,0 +1,136 @@
|
||||
import { Box } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import { generateArithmeticSequence } from './service';
|
||||
import * as Yup from 'yup';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
|
||||
type InitialValuesType = {
|
||||
firstTerm: string;
|
||||
commonDifference: string;
|
||||
numberOfTerms: string;
|
||||
separator: string;
|
||||
};
|
||||
|
||||
const initialValues: InitialValuesType = {
|
||||
firstTerm: '1',
|
||||
commonDifference: '2',
|
||||
numberOfTerms: '10',
|
||||
separator: ', '
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
firstTerm: Yup.number().required('First term is required'),
|
||||
commonDifference: Yup.number().required('Common difference is required'),
|
||||
numberOfTerms: Yup.number()
|
||||
.min(1, 'Must generate at least 1 term')
|
||||
.max(1000, 'Maximum 1000 terms allowed')
|
||||
.required('Number of terms is required'),
|
||||
separator: Yup.string().required('Separator is required')
|
||||
});
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Basic Arithmetic Sequence',
|
||||
description:
|
||||
'Generate a sequence starting at 1, increasing by 2, for 5 terms',
|
||||
sampleOptions: {
|
||||
firstTerm: '1',
|
||||
commonDifference: '2',
|
||||
numberOfTerms: '5',
|
||||
separator: ', '
|
||||
},
|
||||
sampleResult: '1, 3, 5, 7, 9'
|
||||
},
|
||||
{
|
||||
title: 'Negative Sequence',
|
||||
description: 'Generate a decreasing sequence starting at 10',
|
||||
sampleOptions: {
|
||||
firstTerm: '10',
|
||||
commonDifference: '-3',
|
||||
numberOfTerms: '4',
|
||||
separator: ' → '
|
||||
},
|
||||
sampleResult: '10 → 7 → 4 → 1'
|
||||
},
|
||||
{
|
||||
title: 'Decimal Sequence',
|
||||
description: 'Generate a sequence with decimal numbers',
|
||||
sampleOptions: {
|
||||
firstTerm: '0.5',
|
||||
commonDifference: '0.5',
|
||||
numberOfTerms: '6',
|
||||
separator: ' '
|
||||
},
|
||||
sampleResult: '0.5 1 1.5 2 2.5 3'
|
||||
}
|
||||
];
|
||||
|
||||
export default function ArithmeticSequence() {
|
||||
const [result, setResult] = useState<string>('');
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
inputComponent={null}
|
||||
resultComponent={
|
||||
<ToolTextResult title="Generated Sequence" value={result} />
|
||||
}
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
exampleCards={exampleCards}
|
||||
toolInfo={{
|
||||
title: 'What is an Arithmetic Sequence?',
|
||||
description:
|
||||
'An arithmetic sequence is a sequence of numbers where the difference between each consecutive term is constant. This constant difference is called the common difference. Given the first term (a₁) and the common difference (d), each term can be found by adding the common difference to the previous term.'
|
||||
}}
|
||||
getGroups={({ values, updateField }) => [
|
||||
{
|
||||
title: 'Sequence Parameters',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
description="First term of the sequence (a₁)"
|
||||
value={values.firstTerm}
|
||||
onOwnChange={(val) => updateField('firstTerm', val)}
|
||||
type="number"
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
description="Common difference between terms (d)"
|
||||
value={values.commonDifference}
|
||||
onOwnChange={(val) => updateField('commonDifference', val)}
|
||||
type="number"
|
||||
/>
|
||||
<TextFieldWithDesc
|
||||
description="Number of terms to generate (n)"
|
||||
value={values.numberOfTerms}
|
||||
onOwnChange={(val) => updateField('numberOfTerms', val)}
|
||||
type="number"
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Output Format',
|
||||
component: (
|
||||
<TextFieldWithDesc
|
||||
description="Separator between terms"
|
||||
value={values.separator}
|
||||
onOwnChange={(val) => updateField('separator', val)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
]}
|
||||
compute={(values) => {
|
||||
const sequence = generateArithmeticSequence(
|
||||
Number(values.firstTerm),
|
||||
Number(values.commonDifference),
|
||||
Number(values.numberOfTerms),
|
||||
values.separator
|
||||
);
|
||||
setResult(sequence);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
21
src/pages/tools/number/arithmetic-sequence/meta.ts
Normal file
21
src/pages/tools/number/arithmetic-sequence/meta.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('number', {
|
||||
name: 'Generate Arithmetic Sequence',
|
||||
path: 'arithmetic-sequence',
|
||||
icon: 'ic:sharp-plus',
|
||||
description:
|
||||
'Generate an arithmetic sequence by specifying the first term (a₁), common difference (d), and number of terms (n). The tool creates a sequence where each number differs from the previous by a constant difference.',
|
||||
shortDescription:
|
||||
'Generate a sequence where each term differs by a constant value.',
|
||||
keywords: [
|
||||
'arithmetic',
|
||||
'sequence',
|
||||
'progression',
|
||||
'numbers',
|
||||
'series',
|
||||
'generate'
|
||||
],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
13
src/pages/tools/number/arithmetic-sequence/service.ts
Normal file
13
src/pages/tools/number/arithmetic-sequence/service.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export function generateArithmeticSequence(
|
||||
firstTerm: number,
|
||||
commonDifference: number,
|
||||
numberOfTerms: number,
|
||||
separator: string
|
||||
): string {
|
||||
const sequence: number[] = [];
|
||||
for (let i = 0; i < numberOfTerms; i++) {
|
||||
const term = firstTerm + i * commonDifference;
|
||||
sequence.push(term);
|
||||
}
|
||||
return sequence.join(separator);
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
import { tool as numberSum } from './sum/meta';
|
||||
import { tool as numberGenerate } from './generate/meta';
|
||||
import { tool as numberArithmeticSequence } from './arithmetic-sequence/meta';
|
||||
|
||||
export const numberTools = [numberSum, numberGenerate];
|
||||
export const numberTools = [numberSum, numberGenerate, numberArithmeticSequence];
|
||||
|
Reference in New Issue
Block a user