mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-16 20:49:30 +02:00
refactor: use ToolContent
This commit is contained in:
48
.idea/workspace.xml
generated
48
.idea/workspace.xml
generated
@@ -4,18 +4,20 @@
|
|||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="refactor: use ToolContent">
|
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: missing tools">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/components/options/CheckboxWithDesc.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/options/CheckboxWithDesc.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/png/compress-png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/png/compress-png/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/duplicate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/duplicate/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/png/convert-jgp-to-png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/png/convert-jgp-to-png/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/index.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/png/create-transparent/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/png/create-transparent/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/truncate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/truncate/index.tsx" 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/pages/tools/list/unwrap/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/unwrap/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/find-most-popular/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/find-most-popular/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/wrap/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/wrap/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/group/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/group/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/index.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/rotate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/rotate/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/quote/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/quote/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/sort/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/sort/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/rot13/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/rot13/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generate/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/rotate/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/rotate/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/remove-duplicate-lines/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/remove-duplicate-lines/index.tsx" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/split/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/split/index.tsx" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/pages/tools/video/gif/change-speed/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/video/gif/change-speed/index.tsx" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -343,15 +345,7 @@
|
|||||||
<workItem from="1741475969294" duration="4215000" />
|
<workItem from="1741475969294" duration="4215000" />
|
||||||
<workItem from="1741494053121" duration="178000" />
|
<workItem from="1741494053121" duration="178000" />
|
||||||
<workItem from="1741537936314" duration="1294000" />
|
<workItem from="1741537936314" duration="1294000" />
|
||||||
<workItem from="1741539602311" duration="2441000" />
|
<workItem from="1741539602311" duration="3899000" />
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00107" summary="fix: docs">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1740324026721</created>
|
|
||||||
<option name="number" value="00107" />
|
|
||||||
<option name="presentableId" value="LOCAL-00107" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1740324026721</updated>
|
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00108" summary="fix: docs">
|
<task id="LOCAL-00108" summary="fix: docs">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -737,7 +731,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1741540939154</updated>
|
<updated>1741540939154</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="156" />
|
<task id="LOCAL-00156" summary="feat: missing tools">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1741542318259</created>
|
||||||
|
<option name="number" value="00156" />
|
||||||
|
<option name="presentableId" value="LOCAL-00156" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1741542318259</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="157" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -784,7 +786,6 @@
|
|||||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
||||||
<option name="CHECK_NEW_TODO" value="false" />
|
<option name="CHECK_NEW_TODO" value="false" />
|
||||||
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
|
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
|
||||||
<MESSAGE value="refact: examples" />
|
|
||||||
<MESSAGE value="fix: examples" />
|
<MESSAGE value="fix: examples" />
|
||||||
<MESSAGE value="feat: json pretty" />
|
<MESSAGE value="feat: json pretty" />
|
||||||
<MESSAGE value="style: tool categories" />
|
<MESSAGE value="style: tool categories" />
|
||||||
@@ -809,7 +810,8 @@
|
|||||||
<MESSAGE value="chore: remove unnecessary files" />
|
<MESSAGE value="chore: remove unnecessary files" />
|
||||||
<MESSAGE value="refactor: validateJson" />
|
<MESSAGE value="refactor: validateJson" />
|
||||||
<MESSAGE value="refactor: use ToolContent" />
|
<MESSAGE value="refactor: use ToolContent" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="refactor: use ToolContent" />
|
<MESSAGE value="feat: missing tools" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="feat: missing tools" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XSLT-Support.FileAssociations.UIState">
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
<expand />
|
<expand />
|
||||||
|
@@ -3,11 +3,11 @@ import React, { useState } from 'react';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import ToolFileInput from '@components/input/ToolFileInput';
|
import ToolFileInput from '@components/input/ToolFileInput';
|
||||||
import ToolFileResult from '@components/result/ToolFileResult';
|
import ToolFileResult from '@components/result/ToolFileResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import imageCompression from 'browser-image-compression';
|
import imageCompression from 'browser-image-compression';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
rate: '50'
|
rate: '50'
|
||||||
@@ -16,7 +16,7 @@ const validationSchema = Yup.object({
|
|||||||
// splitSeparator: Yup.string().required('The separator is required')
|
// splitSeparator: Yup.string().required('The separator is required')
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function ChangeColorsInPng() {
|
export default function ChangeColorsInPng({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<File | null>(null);
|
const [input, setInput] = useState<File | null>(null);
|
||||||
const [result, setResult] = useState<File | null>(null);
|
const [result, setResult] = useState<File | null>(null);
|
||||||
const [originalSize, setOriginalSize] = useState<number | null>(null); // Store original file size
|
const [originalSize, setOriginalSize] = useState<number | null>(null); // Store original file size
|
||||||
@@ -52,62 +52,60 @@ export default function ChangeColorsInPng() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolFileInput
|
inputComponent={
|
||||||
value={input}
|
<ToolFileInput
|
||||||
onChange={setInput}
|
value={input}
|
||||||
accept={['image/png']}
|
onChange={setInput}
|
||||||
title={'Input PNG'}
|
accept={['image/png']}
|
||||||
/>
|
title={'Input PNG'}
|
||||||
}
|
/>
|
||||||
result={
|
}
|
||||||
<ToolFileResult
|
resultComponent={
|
||||||
title={'Compressed PNG'}
|
<ToolFileResult
|
||||||
value={result}
|
title={'Compressed PNG'}
|
||||||
extension={'png'}
|
value={result}
|
||||||
/>
|
extension={'png'}
|
||||||
}
|
/>
|
||||||
/>
|
}
|
||||||
<ToolOptions
|
initialValues={initialValues}
|
||||||
compute={compute}
|
getGroups={({ values, updateField }) => [
|
||||||
getGroups={({ values, updateField }) => [
|
{
|
||||||
{
|
title: 'Compression options',
|
||||||
title: 'Compression options',
|
component: (
|
||||||
component: (
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.rate}
|
||||||
|
onOwnChange={(val) => updateField('rate', val)}
|
||||||
|
description={'Compression rate (1-100)'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'File sizes',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
<Box>
|
<Box>
|
||||||
<TextFieldWithDesc
|
{originalSize !== null && (
|
||||||
value={values.rate}
|
<Typography>
|
||||||
onOwnChange={(val) => updateField('rate', val)}
|
Original Size: {(originalSize / 1024).toFixed(2)} KB
|
||||||
description={'Compression rate (1-100)'}
|
</Typography>
|
||||||
/>
|
)}
|
||||||
|
{compressedSize !== null && (
|
||||||
|
<Typography>
|
||||||
|
Compressed Size: {(compressedSize / 1024).toFixed(2)} KB
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
</Box>
|
||||||
},
|
)
|
||||||
{
|
}
|
||||||
title: 'File sizes',
|
]}
|
||||||
component: (
|
compute={compute}
|
||||||
<Box>
|
setInput={setInput}
|
||||||
<Box>
|
/>
|
||||||
{originalSize !== null && (
|
|
||||||
<Typography>
|
|
||||||
Original Size: {(originalSize / 1024).toFixed(2)} KB
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
{compressedSize !== null && (
|
|
||||||
<Typography>
|
|
||||||
Compressed Size: {(compressedSize / 1024).toFixed(2)} KB
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import ToolInputAndResult from 'components/ToolInputAndResult';
|
|
||||||
import ToolFileInput from 'components/input/ToolFileInput';
|
import ToolFileInput from 'components/input/ToolFileInput';
|
||||||
import CheckboxWithDesc from 'components/options/CheckboxWithDesc';
|
import CheckboxWithDesc from 'components/options/CheckboxWithDesc';
|
||||||
import ColorSelector from 'components/options/ColorSelector';
|
import ColorSelector from 'components/options/ColorSelector';
|
||||||
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
||||||
import ToolOptions from 'components/options/ToolOptions';
|
|
||||||
import ToolFileResult from 'components/result/ToolFileResult';
|
import ToolFileResult from 'components/result/ToolFileResult';
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { areColorsSimilar } from 'utils/color';
|
import { areColorsSimilar } from 'utils/color';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
enableTransparency: false,
|
enableTransparency: false,
|
||||||
@@ -19,7 +19,7 @@ const initialValues = {
|
|||||||
const validationSchema = Yup.object({
|
const validationSchema = Yup.object({
|
||||||
// splitSeparator: Yup.string().required('The separator is required')
|
// splitSeparator: Yup.string().required('The separator is required')
|
||||||
});
|
});
|
||||||
export default function ConvertJgpToPng() {
|
export default function ConvertJgpToPng({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<File | null>(null);
|
const [input, setInput] = useState<File | null>(null);
|
||||||
const [result, setResult] = useState<File | null>(null);
|
const [result, setResult] = useState<File | null>(null);
|
||||||
|
|
||||||
@@ -97,58 +97,52 @@ export default function ConvertJgpToPng() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolFileInput
|
inputComponent={
|
||||||
value={input}
|
<ToolFileInput
|
||||||
onChange={setInput}
|
value={input}
|
||||||
accept={['image/jpeg']}
|
onChange={setInput}
|
||||||
title={'Input JPG'}
|
accept={['image/jpeg']}
|
||||||
/>
|
title={'Input JPG'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
resultComponent={
|
||||||
|
<ToolFileResult title={'Output PNG'} value={result} extension={'png'} />
|
||||||
|
}
|
||||||
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'PNG Transparency Color',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
key="enableTransparency"
|
||||||
|
title="Enable PNG Transparency"
|
||||||
|
checked={!!values.enableTransparency}
|
||||||
|
onChange={(value) => updateField('enableTransparency', value)}
|
||||||
|
description="Make the color below transparent."
|
||||||
|
/>
|
||||||
|
<ColorSelector
|
||||||
|
value={values.color}
|
||||||
|
onColorChange={(val) => updateField('color', val)}
|
||||||
|
description={'With this color (to color)'}
|
||||||
|
inputProps={{ 'data-testid': 'color-input' }}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.similarity}
|
||||||
|
onOwnChange={(val) => updateField('similarity', val)}
|
||||||
|
description={
|
||||||
|
'Match this % of similar. For example, 10% white will match white and a little bit of gray.'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result={
|
]}
|
||||||
<ToolFileResult
|
compute={compute}
|
||||||
title={'Output PNG'}
|
setInput={setInput}
|
||||||
value={result}
|
/>
|
||||||
extension={'png'}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ToolOptions
|
|
||||||
compute={compute}
|
|
||||||
getGroups={({ values, updateField }) => [
|
|
||||||
{
|
|
||||||
title: 'PNG Transparency Color',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
key="enableTransparency"
|
|
||||||
title="Enable PNG Transparency"
|
|
||||||
checked={!!values.enableTransparency}
|
|
||||||
onChange={(value) => updateField('enableTransparency', value)}
|
|
||||||
description="Make the color below transparent."
|
|
||||||
/>
|
|
||||||
<ColorSelector
|
|
||||||
value={values.color}
|
|
||||||
onColorChange={(val) => updateField('color', val)}
|
|
||||||
description={'With this color (to color)'}
|
|
||||||
inputProps={{ 'data-testid': 'color-input' }}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.similarity}
|
|
||||||
onOwnChange={(val) => updateField('similarity', val)}
|
|
||||||
description={
|
|
||||||
'Match this % of similar. For example, 10% white will match white and a little bit of gray.'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -3,21 +3,24 @@ import React, { useState } from 'react';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import ToolFileInput from '@components/input/ToolFileInput';
|
import ToolFileInput from '@components/input/ToolFileInput';
|
||||||
import ToolFileResult from '@components/result/ToolFileResult';
|
import ToolFileResult from '@components/result/ToolFileResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import ColorSelector from '@components/options/ColorSelector';
|
import ColorSelector from '@components/options/ColorSelector';
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import { areColorsSimilar } from 'utils/color';
|
import { areColorsSimilar } from 'utils/color';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
fromColor: 'white',
|
fromColor: 'white',
|
||||||
similarity: '10'
|
similarity: '10'
|
||||||
};
|
};
|
||||||
|
|
||||||
const validationSchema = Yup.object({
|
const validationSchema = Yup.object({
|
||||||
// splitSeparator: Yup.string().required('The separator is required')
|
// splitSeparator: Yup.string().required('The separator is required')
|
||||||
});
|
});
|
||||||
export default function ChangeColorsInPng() {
|
|
||||||
|
export default function CreateTransparent({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<File | null>(null);
|
const [input, setInput] = useState<File | null>(null);
|
||||||
const [result, setResult] = useState<File | null>(null);
|
const [result, setResult] = useState<File | null>(null);
|
||||||
|
|
||||||
@@ -76,52 +79,60 @@ export default function ChangeColorsInPng() {
|
|||||||
processImage(input, fromRgb, Number(similarity));
|
processImage(input, fromRgb, Number(similarity));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getGroups: GetGroupsType<typeof initialValues> = ({
|
||||||
|
values,
|
||||||
|
updateField
|
||||||
|
}) => [
|
||||||
|
{
|
||||||
|
title: 'From color and similarity',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<ColorSelector
|
||||||
|
value={values.fromColor}
|
||||||
|
onColorChange={(val) => updateField('fromColor', val)}
|
||||||
|
description={'Replace this color (from color)'}
|
||||||
|
inputProps={{ 'data-testid': 'color-input' }}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.similarity}
|
||||||
|
onOwnChange={(val) => updateField('similarity', val)}
|
||||||
|
description={
|
||||||
|
'Match this % of similar colors of the from color. For example, 10% white will match white and a little bit of gray.'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
inputComponent={
|
||||||
<ToolFileInput
|
<ToolFileInput
|
||||||
value={input}
|
value={input}
|
||||||
onChange={setInput}
|
onChange={setInput}
|
||||||
accept={['image/png']}
|
accept={['image/png']}
|
||||||
title={'Input PNG'}
|
title={'Input PNG'}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
result={
|
resultComponent={
|
||||||
<ToolFileResult
|
<ToolFileResult
|
||||||
title={'Transparent PNG'}
|
title={'Transparent PNG'}
|
||||||
value={result}
|
value={result}
|
||||||
extension={'png'}
|
extension={'png'}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
initialValues={initialValues}
|
||||||
<ToolOptions
|
getGroups={getGroups}
|
||||||
compute={compute}
|
compute={compute}
|
||||||
getGroups={({ values, updateField }) => [
|
input={input}
|
||||||
{
|
validationSchema={validationSchema}
|
||||||
title: 'From color and similarity',
|
toolInfo={{
|
||||||
component: (
|
title: 'Create Transparent PNG',
|
||||||
<Box>
|
description:
|
||||||
<ColorSelector
|
'This tool allows you to make specific colors in a PNG image transparent. You can select the color to replace and adjust the similarity threshold to include similar colors.'
|
||||||
value={values.fromColor}
|
}}
|
||||||
onColorChange={(val) => updateField('fromColor', val)}
|
/>
|
||||||
description={'Replace this color (from color)'}
|
|
||||||
inputProps={{ 'data-testid': 'color-input' }}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.similarity}
|
|
||||||
onOwnChange={(val) => updateField('similarity', val)}
|
|
||||||
description={
|
|
||||||
'Match this % of similar colors of the from color. For example, 10% white will match white and a little bit of gray.'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,7 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions, { GetGroupsType } from '@components/options/ToolOptions';
|
|
||||||
import { beautifyJson } from './service';
|
import { beautifyJson } from './service';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
|
|
||||||
import ToolInfo from '@components/ToolInfo';
|
import ToolInfo from '@components/ToolInfo';
|
||||||
import Separator from '@components/Separator';
|
import Separator from '@components/Separator';
|
||||||
import ToolExamples, {
|
import ToolExamples, {
|
||||||
@@ -16,6 +13,7 @@ import { ToolComponentProps } from '@tools/defineTool';
|
|||||||
import RadioWithTextField from '@components/options/RadioWithTextField';
|
import RadioWithTextField from '@components/options/RadioWithTextField';
|
||||||
import SimpleRadio from '@components/options/SimpleRadio';
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
import { isNumber, updateNumberField } from '../../../../utils/string';
|
import { isNumber, updateNumberField } from '../../../../utils/string';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
|
||||||
type InitialValuesType = {
|
type InitialValuesType = {
|
||||||
indentationType: 'tab' | 'space';
|
indentationType: 'tab' | 'space';
|
||||||
@@ -119,72 +117,63 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
|
|||||||
export default function PrettifyJson({ title }: ToolComponentProps) {
|
export default function PrettifyJson({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const formRef = useRef<FormikProps<InitialValuesType>>(null);
|
|
||||||
const compute = (optionsValues: InitialValuesType, input: any) => {
|
const compute = (optionsValues: InitialValuesType, input: any) => {
|
||||||
const { indentationType, spacesCount } = optionsValues;
|
const { indentationType, spacesCount } = optionsValues;
|
||||||
if (input) setResult(beautifyJson(input, indentationType, spacesCount));
|
if (input) setResult(beautifyJson(input, indentationType, spacesCount));
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGroups: GetGroupsType<InitialValuesType> = ({
|
|
||||||
values,
|
|
||||||
updateField
|
|
||||||
}) => [
|
|
||||||
{
|
|
||||||
title: 'Indentation',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<RadioWithTextField
|
|
||||||
checked={values.indentationType === 'space'}
|
|
||||||
title={'Use Spaces'}
|
|
||||||
fieldName={'indentationType'}
|
|
||||||
description={'Indent output with spaces'}
|
|
||||||
value={values.spacesCount.toString()}
|
|
||||||
onRadioClick={() => updateField('indentationType', 'space')}
|
|
||||||
onTextChange={(val) =>
|
|
||||||
updateNumberField(val, 'spacesCount', updateField)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SimpleRadio
|
|
||||||
onClick={() => updateField('indentationType', 'tab')}
|
|
||||||
checked={values.indentationType === 'tab'}
|
|
||||||
description={'Indent output with tabs.'}
|
|
||||||
title={'Use Tabs'}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<ToolInputAndResult
|
<ToolContent
|
||||||
input={
|
title={title}
|
||||||
|
input={input}
|
||||||
|
inputComponent={
|
||||||
<ToolTextInput
|
<ToolTextInput
|
||||||
title={'Input JSON'}
|
title={'Input JSON'}
|
||||||
value={input}
|
value={input}
|
||||||
onChange={setInput}
|
onChange={setInput}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
result={<ToolTextResult title={'Pretty JSON'} value={result} />}
|
resultComponent={
|
||||||
/>
|
<ToolTextResult title={'Pretty JSON'} value={result} />
|
||||||
<ToolOptions
|
}
|
||||||
formRef={formRef}
|
|
||||||
compute={compute}
|
|
||||||
getGroups={getGroups}
|
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
input={input}
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'Indentation',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<RadioWithTextField
|
||||||
|
checked={values.indentationType === 'space'}
|
||||||
|
title={'Use Spaces'}
|
||||||
|
fieldName={'indentationType'}
|
||||||
|
description={'Indent output with spaces'}
|
||||||
|
value={values.spacesCount.toString()}
|
||||||
|
onRadioClick={() => updateField('indentationType', 'space')}
|
||||||
|
onTextChange={(val) =>
|
||||||
|
updateNumberField(val, 'spacesCount', updateField)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<SimpleRadio
|
||||||
|
onClick={() => updateField('indentationType', 'tab')}
|
||||||
|
checked={values.indentationType === 'tab'}
|
||||||
|
description={'Indent output with tabs.'}
|
||||||
|
title={'Use Tabs'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
compute={compute}
|
||||||
|
setInput={setInput}
|
||||||
|
exampleCards={exampleCards}
|
||||||
/>
|
/>
|
||||||
<ToolInfo
|
<ToolInfo
|
||||||
title="What Is a JSON Prettifier?"
|
title="What Is a JSON Prettifier?"
|
||||||
description="This tool adds consistent formatting to the data in JavaScript Object Notation (JSON) format. This transformation makes the JSON code more readable, making it easier to understand and edit. The program parses the JSON data structure into tokens and then reformats them by adding indentation and line breaks. If the data is hierarchial, then it adds indentation at the beginning of lines to visually show the depth of the JSON and adds newlines to break long single-line JSON arrays into multiple shorter, more readable ones. Additionally, this utility can remove unnecessary spaces and tabs from your JSON code (especially leading and trailing whitespaces), making it more compact. You can choose the line indentation method in the options: indent with spaces or indent with tabs. When using spaces, you can also specify how many spaces to use for each indentation level (usually 2 or 4 spaces). "
|
description="This tool adds consistent formatting to the data in JavaScript Object Notation (JSON) format. This transformation makes the JSON code more readable, making it easier to understand and edit. The program parses the JSON data structure into tokens and then reformats them by adding indentation and line breaks. If the data is hierarchial, then it adds indentation at the beginning of lines to visually show the depth of the JSON and adds newlines to break long single-line JSON arrays into multiple shorter, more readable ones. Additionally, this utility can remove unnecessary spaces and tabs from your JSON code (especially leading and trailing whitespaces), making it more compact. You can choose the line indentation method in the options: indent with spaces or indent with tabs. When using spaces, you can also specify how many spaces to use for each indentation level (usually 2 or 4 spaces). "
|
||||||
/>
|
/>
|
||||||
<Separator backgroundColor="#5581b5" margin="50px" />
|
<Separator backgroundColor="#5581b5" margin="50px" />
|
||||||
<ToolExamples
|
|
||||||
title={title}
|
|
||||||
exampleCards={exampleCards}
|
|
||||||
getGroups={getGroups}
|
|
||||||
formRef={formRef}
|
|
||||||
setInput={setInput}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,18 +2,18 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import {
|
import {
|
||||||
DisplayFormat,
|
DisplayFormat,
|
||||||
SortingMethod,
|
SortingMethod,
|
||||||
SplitOperatorType,
|
SplitOperatorType,
|
||||||
TopItemsList
|
TopItemsList
|
||||||
} from './service';
|
} from './service';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import SimpleRadio from '@components/options/SimpleRadio';
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||||
import SelectWithDesc from '@components/options/SelectWithDesc';
|
import SelectWithDesc from '@components/options/SelectWithDesc';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||||
@@ -41,7 +41,7 @@ const splitOperators: {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function FindMostPopular() {
|
export default function FindMostPopular({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const compute = (optionsValues: typeof initialValues, input: any) => {
|
const compute = (optionsValues: typeof initialValues, input: any) => {
|
||||||
@@ -70,98 +70,94 @@ export default function FindMostPopular() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolTextInput
|
inputComponent={
|
||||||
title={'Input list'}
|
<ToolTextInput title={'Input list'} value={input} onChange={setInput} />
|
||||||
value={input}
|
}
|
||||||
onChange={setInput}
|
resultComponent={
|
||||||
/>
|
<ToolTextResult title={'Most popular items'} value={result} />
|
||||||
|
}
|
||||||
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'How to Extract List Items?',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
{splitOperators.map(({ title, description, type }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={type}
|
||||||
|
onClick={() => updateField('splitSeparatorType', type)}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
checked={values.splitSeparatorType === type}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Set a delimiting symbol or regular expression.'}
|
||||||
|
value={values.splitSeparator}
|
||||||
|
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Item comparison',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Remove empty items'}
|
||||||
|
description={'Ignore empty items from comparison.'}
|
||||||
|
checked={values.deleteEmptyItems}
|
||||||
|
onChange={(value) => updateField('deleteEmptyItems', value)}
|
||||||
|
/>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Trim top list items'}
|
||||||
|
description={
|
||||||
|
'Remove leading and trailing spaces before comparing items'
|
||||||
|
}
|
||||||
|
checked={values.trimItems}
|
||||||
|
onChange={(value) => updateField('trimItems', value)}
|
||||||
|
/>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Ignore Item Case'}
|
||||||
|
description={'Compare all list items in lowercase.'}
|
||||||
|
checked={values.ignoreItemCase}
|
||||||
|
onChange={(value) => updateField('ignoreItemCase', value)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Top item output format',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<SelectWithDesc
|
||||||
|
selected={values.displayFormat}
|
||||||
|
options={[
|
||||||
|
{ label: 'Show item percentage', value: 'percentage' },
|
||||||
|
{ label: 'Show item count', value: 'count' },
|
||||||
|
{ label: 'Show item total', value: 'total' }
|
||||||
|
]}
|
||||||
|
onChange={(value) => updateField('displayFormat', value)}
|
||||||
|
description={'How to display the most popular list items?'}
|
||||||
|
/>
|
||||||
|
<SelectWithDesc
|
||||||
|
selected={values.sortingMethod}
|
||||||
|
options={[
|
||||||
|
{ label: 'Sort Alphabetically', value: 'alphabetic' },
|
||||||
|
{ label: 'Sort by count', value: 'count' }
|
||||||
|
]}
|
||||||
|
onChange={(value) => updateField('sortingMethod', value)}
|
||||||
|
description={'Select a sorting method.'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result={<ToolTextResult title={'Most popular items'} value={result} />}
|
]}
|
||||||
/>
|
compute={compute}
|
||||||
<ToolOptions
|
setInput={setInput}
|
||||||
compute={compute}
|
/>
|
||||||
getGroups={({ values, updateField }) => [
|
|
||||||
{
|
|
||||||
title: 'How to Extract List Items?',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
{splitOperators.map(({ title, description, type }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={type}
|
|
||||||
onClick={() => updateField('splitSeparatorType', type)}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
checked={values.splitSeparatorType === type}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Set a delimiting symbol or regular expression.'}
|
|
||||||
value={values.splitSeparator}
|
|
||||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Item comparison',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Remove empty items'}
|
|
||||||
description={'Ignore empty items from comparison.'}
|
|
||||||
checked={values.deleteEmptyItems}
|
|
||||||
onChange={(value) => updateField('deleteEmptyItems', value)}
|
|
||||||
/>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Trim top list items'}
|
|
||||||
description={
|
|
||||||
'Remove leading and trailing spaces before comparing items'
|
|
||||||
}
|
|
||||||
checked={values.trimItems}
|
|
||||||
onChange={(value) => updateField('trimItems', value)}
|
|
||||||
/>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Ignore Item Case'}
|
|
||||||
description={'Compare all list items in lowercase.'}
|
|
||||||
checked={values.ignoreItemCase}
|
|
||||||
onChange={(value) => updateField('ignoreItemCase', value)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Top item output format',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<SelectWithDesc
|
|
||||||
selected={values.displayFormat}
|
|
||||||
options={[
|
|
||||||
{ label: 'Show item percentage', value: 'percentage' },
|
|
||||||
{ label: 'Show item count', value: 'count' },
|
|
||||||
{ label: 'Show item total', value: 'total' }
|
|
||||||
]}
|
|
||||||
onChange={(value) => updateField('displayFormat', value)}
|
|
||||||
description={'How to display the most popular list items?'}
|
|
||||||
/>
|
|
||||||
<SelectWithDesc
|
|
||||||
selected={values.sortingMethod}
|
|
||||||
options={[
|
|
||||||
{ label: 'Sort Alphabetically', value: 'alphabetic' },
|
|
||||||
{ label: 'Sort by count', value: 'count' }
|
|
||||||
]}
|
|
||||||
onChange={(value) => updateField('sortingMethod', value)}
|
|
||||||
description={'Select a sorting method.'}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,13 +2,13 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import { groupList, SplitOperatorType } from './service';
|
import { groupList, SplitOperatorType } from './service';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import SimpleRadio from '@components/options/SimpleRadio';
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||||
import { formatNumber } from '../../../../utils/number';
|
import { formatNumber } from '../../../../utils/number';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
splitOperatorType: 'symbol' as SplitOperatorType,
|
splitOperatorType: 'symbol' as SplitOperatorType,
|
||||||
@@ -39,7 +39,7 @@ const splitOperators: {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function FindUnique() {
|
export default function FindUnique({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const compute = (optionsValues: typeof initialValues, input: any) => {
|
const compute = (optionsValues: typeof initialValues, input: any) => {
|
||||||
@@ -74,110 +74,106 @@ export default function FindUnique() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolTextInput
|
inputComponent={
|
||||||
title={'Input list'}
|
<ToolTextInput title={'Input list'} value={input} onChange={setInput} />
|
||||||
value={input}
|
}
|
||||||
onChange={setInput}
|
resultComponent={
|
||||||
/>
|
<ToolTextResult title={'Grouped items'} value={result} />
|
||||||
|
}
|
||||||
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'Input Item Separator',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
{splitOperators.map(({ title, description, type }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={type}
|
||||||
|
onClick={() => updateField('splitOperatorType', type)}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
checked={values.splitOperatorType === type}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Set a delimiting symbol or regular expression.'}
|
||||||
|
value={values.splitSeparator}
|
||||||
|
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Group Size and Separators',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.groupNumber}
|
||||||
|
description={'Number of items in a group'}
|
||||||
|
type={'number'}
|
||||||
|
onOwnChange={(value) =>
|
||||||
|
updateField('groupNumber', formatNumber(value, 1))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.itemSeparator}
|
||||||
|
description={'Item separator character'}
|
||||||
|
onOwnChange={(value) => updateField('itemSeparator', value)}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.groupSeparator}
|
||||||
|
description={'Group separator character'}
|
||||||
|
onOwnChange={(value) => updateField('groupSeparator', value)}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.leftWrap}
|
||||||
|
description={"Group's left wrap symbol."}
|
||||||
|
onOwnChange={(value) => updateField('leftWrap', value)}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.rightWrap}
|
||||||
|
description={"Group's right wrap symbol."}
|
||||||
|
onOwnChange={(value) => updateField('rightWrap', value)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Empty Items and Padding',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Delete Empty Items'}
|
||||||
|
description={
|
||||||
|
"Ignore empty items and don't include them in the groups."
|
||||||
|
}
|
||||||
|
checked={values.deleteEmptyItems}
|
||||||
|
onChange={(value) => updateField('deleteEmptyItems', value)}
|
||||||
|
/>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Pad Non-full Groups'}
|
||||||
|
description={
|
||||||
|
'Fill non-full groups with a custom item (enter below).'
|
||||||
|
}
|
||||||
|
checked={values.padNonFullGroup}
|
||||||
|
onChange={(value) => updateField('padNonFullGroup', value)}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.paddingChar}
|
||||||
|
description={
|
||||||
|
'Use this character or item to pad non-full groups.'
|
||||||
|
}
|
||||||
|
onOwnChange={(value) => updateField('paddingChar', value)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result={<ToolTextResult title={'Grouped items'} value={result} />}
|
]}
|
||||||
/>
|
compute={compute}
|
||||||
<ToolOptions
|
setInput={setInput}
|
||||||
compute={compute}
|
/>
|
||||||
getGroups={({ values, updateField }) => [
|
|
||||||
{
|
|
||||||
title: 'Input Item Separator',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
{splitOperators.map(({ title, description, type }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={type}
|
|
||||||
onClick={() => updateField('splitOperatorType', type)}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
checked={values.splitOperatorType === type}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Set a delimiting symbol or regular expression.'}
|
|
||||||
value={values.splitSeparator}
|
|
||||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Group Size and Separators',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.groupNumber}
|
|
||||||
description={'Number of items in a group'}
|
|
||||||
type={'number'}
|
|
||||||
onOwnChange={(value) =>
|
|
||||||
updateField('groupNumber', formatNumber(value, 1))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.itemSeparator}
|
|
||||||
description={'Item separator character'}
|
|
||||||
onOwnChange={(value) => updateField('itemSeparator', value)}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.groupSeparator}
|
|
||||||
description={'Group separator character'}
|
|
||||||
onOwnChange={(value) => updateField('groupSeparator', value)}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.leftWrap}
|
|
||||||
description={"Group's left wrap symbol."}
|
|
||||||
onOwnChange={(value) => updateField('leftWrap', value)}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.rightWrap}
|
|
||||||
description={"Group's right wrap symbol."}
|
|
||||||
onOwnChange={(value) => updateField('rightWrap', value)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Empty Items and Padding',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Delete Empty Items'}
|
|
||||||
description={
|
|
||||||
"Ignore empty items and don't include them in the groups."
|
|
||||||
}
|
|
||||||
checked={values.deleteEmptyItems}
|
|
||||||
onChange={(value) => updateField('deleteEmptyItems', value)}
|
|
||||||
/>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Pad Non-full Groups'}
|
|
||||||
description={
|
|
||||||
'Fill non-full groups with a custom item (enter below).'
|
|
||||||
}
|
|
||||||
checked={values.padNonFullGroup}
|
|
||||||
onChange={(value) => updateField('padNonFullGroup', value)}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.paddingChar}
|
|
||||||
description={
|
|
||||||
'Use this character or item to pad non-full groups.'
|
|
||||||
}
|
|
||||||
onOwnChange={(value) => updateField('paddingChar', value)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,12 +2,12 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import { rotateList, SplitOperatorType } from './service';
|
import { rotateList, SplitOperatorType } from './service';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import SimpleRadio from '@components/options/SimpleRadio';
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
import { formatNumber } from '../../../../utils/number';
|
import { formatNumber } from '../../../../utils/number';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
splitOperatorType: 'symbol' as SplitOperatorType,
|
splitOperatorType: 'symbol' as SplitOperatorType,
|
||||||
@@ -52,7 +52,7 @@ const rotationDirections: {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Rotate() {
|
export default function Rotate({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const compute = (optionsValues: typeof initialValues, input: any) => {
|
const compute = (optionsValues: typeof initialValues, input: any) => {
|
||||||
@@ -72,82 +72,74 @@ export default function Rotate() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolTextInput
|
inputComponent={
|
||||||
title={'Input list'}
|
<ToolTextInput title={'Input list'} value={input} onChange={setInput} />
|
||||||
value={input}
|
}
|
||||||
onChange={setInput}
|
resultComponent={<ToolTextResult title={'Rotated list'} value={result} />}
|
||||||
/>
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'Item split mode',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
{splitOperators.map(({ title, description, type }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={type}
|
||||||
|
onClick={() => updateField('splitOperatorType', type)}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
checked={values.splitOperatorType === type}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Set a delimiting symbol or regular expression.'}
|
||||||
|
value={values.splitSeparator}
|
||||||
|
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Rotation Direction and Count',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
{rotationDirections.map(({ title, description, value }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={`${value}`}
|
||||||
|
onClick={() => updateField('right', value)}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
checked={values.right === value}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Number of items to rotate'}
|
||||||
|
value={values.step}
|
||||||
|
onOwnChange={(val) => updateField('step', formatNumber(val, 1))}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Rotated List Joining Symbol',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.joinSeparator}
|
||||||
|
onOwnChange={(value) => updateField('joinSeparator', value)}
|
||||||
|
description={
|
||||||
|
'Enter the character that goes between items in the rotated list.'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result={<ToolTextResult title={'Rotated list'} value={result} />}
|
]}
|
||||||
/>
|
compute={compute}
|
||||||
<ToolOptions
|
setInput={setInput}
|
||||||
compute={compute}
|
/>
|
||||||
getGroups={({ values, updateField }) => [
|
|
||||||
{
|
|
||||||
title: 'Item split mode',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
{splitOperators.map(({ title, description, type }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={type}
|
|
||||||
onClick={() => updateField('splitOperatorType', type)}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
checked={values.splitOperatorType === type}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Set a delimiting symbol or regular expression.'}
|
|
||||||
value={values.splitSeparator}
|
|
||||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Rotation Direction and Count',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
{rotationDirections.map(({ title, description, value }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={`${value}`}
|
|
||||||
onClick={() => updateField('right', value)}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
checked={values.right === value}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Number of items to rotate'}
|
|
||||||
value={values.step}
|
|
||||||
onOwnChange={(val) =>
|
|
||||||
updateField('step', formatNumber(val, 1))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Rotated List Joining Symbol',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.joinSeparator}
|
|
||||||
onOwnChange={(value) => updateField('joinSeparator', value)}
|
|
||||||
description={
|
|
||||||
'Enter the character that goes between items in the rotated list.'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,13 +2,13 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import { Sort, SortingMethod, SplitOperatorType } from './service';
|
import { Sort, SortingMethod, SplitOperatorType } from './service';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import SimpleRadio from '@components/options/SimpleRadio';
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||||
import SelectWithDesc from '@components/options/SelectWithDesc';
|
import SelectWithDesc from '@components/options/SelectWithDesc';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||||
@@ -36,7 +36,7 @@ const splitOperators: {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function SplitText() {
|
export default function SplitText({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const compute = (optionsValues: typeof initialValues, input: any) => {
|
const compute = (optionsValues: typeof initialValues, input: any) => {
|
||||||
@@ -65,101 +65,95 @@ export default function SplitText() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolTextInput
|
inputComponent={
|
||||||
title={'Input list'}
|
<ToolTextInput title={'Input list'} value={input} onChange={setInput} />
|
||||||
value={input}
|
}
|
||||||
onChange={setInput}
|
resultComponent={<ToolTextResult title={'Sorted list'} value={result} />}
|
||||||
/>
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'Input item separator',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
{splitOperators.map(({ title, description, type }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={type}
|
||||||
|
onClick={() => updateField('splitSeparatorType', type)}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
checked={values.splitSeparatorType === type}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Set a delimiting symbol or regular expression.'}
|
||||||
|
value={values.splitSeparator}
|
||||||
|
onOwnChange={(val) => updateField('splitSeparator', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Sort method',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<SelectWithDesc
|
||||||
|
selected={values.sortingMethod}
|
||||||
|
options={[
|
||||||
|
{ label: 'Sort Alphabetically', value: 'alphabetic' },
|
||||||
|
{ label: 'Sort Numerically', value: 'numeric' },
|
||||||
|
{ label: 'Sort by Length', value: 'length' }
|
||||||
|
]}
|
||||||
|
onChange={(value) => updateField('sortingMethod', value)}
|
||||||
|
description={'Select a sorting method.'}
|
||||||
|
/>
|
||||||
|
<SelectWithDesc
|
||||||
|
selected={values.increasing}
|
||||||
|
options={[
|
||||||
|
{ label: 'Increasing order', value: true },
|
||||||
|
{ label: 'Decreasing order', value: false }
|
||||||
|
]}
|
||||||
|
onChange={(value) => {
|
||||||
|
updateField('increasing', value);
|
||||||
|
}}
|
||||||
|
description={'Select a sorting order.'}
|
||||||
|
/>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Case Sensitive Sort'}
|
||||||
|
description={
|
||||||
|
'Sort uppercase and lowercase items separately. Capital letters precede lowercase letters in an ascending list. (Works only in alphabetical sorting mode.)'
|
||||||
|
}
|
||||||
|
checked={values.caseSensitive}
|
||||||
|
onChange={(val) => updateField('caseSensitive', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Sorted item properties',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={
|
||||||
|
'Use this symbol as a joiner between items in a sorted list.'
|
||||||
|
}
|
||||||
|
value={values.joinSeparator}
|
||||||
|
onOwnChange={(val) => updateField('joinSeparator', val)}
|
||||||
|
/>
|
||||||
|
<CheckboxWithDesc
|
||||||
|
title={'Remove duplicates'}
|
||||||
|
description={'Delete duplicate list items.'}
|
||||||
|
checked={values.removeDuplicated}
|
||||||
|
onChange={(val) => updateField('removeDuplicated', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result={<ToolTextResult title={'Sorted list'} value={result} />}
|
]}
|
||||||
/>
|
compute={compute}
|
||||||
<ToolOptions
|
setInput={setInput}
|
||||||
compute={compute}
|
/>
|
||||||
getGroups={({ values, updateField }) => [
|
|
||||||
{
|
|
||||||
title: 'Input item separator',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
{splitOperators.map(({ title, description, type }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={type}
|
|
||||||
onClick={() => updateField('splitSeparatorType', type)}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
checked={values.splitSeparatorType === type}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Set a delimiting symbol or regular expression.'}
|
|
||||||
value={values.splitSeparator}
|
|
||||||
onOwnChange={(val) => updateField('splitSeparator', val)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Sort method',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<SelectWithDesc
|
|
||||||
selected={values.sortingMethod}
|
|
||||||
options={[
|
|
||||||
{ label: 'Sort Alphabetically', value: 'alphabetic' },
|
|
||||||
{ label: 'Sort Numerically', value: 'numeric' },
|
|
||||||
{ label: 'Sort by Length', value: 'length' }
|
|
||||||
]}
|
|
||||||
onChange={(value) => updateField('sortingMethod', value)}
|
|
||||||
description={'Select a sorting method.'}
|
|
||||||
/>
|
|
||||||
<SelectWithDesc
|
|
||||||
selected={values.increasing}
|
|
||||||
options={[
|
|
||||||
{ label: 'Increasing order', value: true },
|
|
||||||
{ label: 'Decreasing order', value: false }
|
|
||||||
]}
|
|
||||||
onChange={(value) => {
|
|
||||||
updateField('increasing', value);
|
|
||||||
}}
|
|
||||||
description={'Select a sorting order.'}
|
|
||||||
/>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Case Sensitive Sort'}
|
|
||||||
description={
|
|
||||||
'Sort uppercase and lowercase items separately. Capital letters precede lowercase letters in an ascending list. (Works only in alphabetical sorting mode.)'
|
|
||||||
}
|
|
||||||
checked={values.caseSensitive}
|
|
||||||
onChange={(val) => updateField('caseSensitive', val)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Sorted item properties',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={
|
|
||||||
'Use this symbol as a joiner between items in a sorted list.'
|
|
||||||
}
|
|
||||||
value={values.joinSeparator}
|
|
||||||
onOwnChange={(val) => updateField('joinSeparator', val)}
|
|
||||||
/>
|
|
||||||
<CheckboxWithDesc
|
|
||||||
title={'Remove duplicates'}
|
|
||||||
description={'Delete duplicate list items.'}
|
|
||||||
checked={values.removeDuplicated}
|
|
||||||
onChange={(val) => updateField('removeDuplicated', val)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import { listOfIntegers } from './service';
|
import { listOfIntegers } from './service';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
firstValue: '1',
|
firstValue: '1',
|
||||||
@@ -12,68 +12,69 @@ const initialValues = {
|
|||||||
step: '1',
|
step: '1',
|
||||||
separator: '\\n'
|
separator: '\\n'
|
||||||
};
|
};
|
||||||
export default function SplitText() {
|
|
||||||
|
export default function GenerateNumbers({ title }: ToolComponentProps) {
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
|
|
||||||
|
const compute = (optionsValues: typeof initialValues) => {
|
||||||
|
const { firstValue, numberOfNumbers, separator, step } = optionsValues;
|
||||||
|
setResult(
|
||||||
|
listOfIntegers(
|
||||||
|
Number(firstValue),
|
||||||
|
Number(numberOfNumbers),
|
||||||
|
Number(step),
|
||||||
|
separator
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
result={<ToolTextResult title={'Total'} value={result} />}
|
initialValues={initialValues}
|
||||||
/>
|
getGroups={({ values, updateField }) => [
|
||||||
<ToolOptions
|
{
|
||||||
getGroups={({ values, updateField }) => [
|
title: 'Arithmetic sequence option',
|
||||||
{
|
component: (
|
||||||
title: 'Arithmetic sequence option',
|
<Box>
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Start sequence from this number.'}
|
|
||||||
value={values.firstValue}
|
|
||||||
onOwnChange={(val) => updateField('firstValue', val)}
|
|
||||||
type={'number'}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Increase each element by this amount'}
|
|
||||||
value={values.step}
|
|
||||||
onOwnChange={(val) => updateField('step', val)}
|
|
||||||
type={'number'}
|
|
||||||
/>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
description={'Number of elements in sequence.'}
|
|
||||||
value={values.numberOfNumbers}
|
|
||||||
onOwnChange={(val) => updateField('numberOfNumbers', val)}
|
|
||||||
type={'number'}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Separator',
|
|
||||||
component: (
|
|
||||||
<TextFieldWithDesc
|
<TextFieldWithDesc
|
||||||
description={
|
description={'Start sequence from this number.'}
|
||||||
'Separate elements in the arithmetic sequence by this character.'
|
value={values.firstValue}
|
||||||
}
|
onOwnChange={(val) => updateField('firstValue', val)}
|
||||||
value={values.separator}
|
type={'number'}
|
||||||
onOwnChange={(val) => updateField('separator', val)}
|
|
||||||
/>
|
/>
|
||||||
)
|
<TextFieldWithDesc
|
||||||
}
|
description={'Increase each element by this amount'}
|
||||||
]}
|
value={values.step}
|
||||||
compute={(optionsValues) => {
|
onOwnChange={(val) => updateField('step', val)}
|
||||||
const { firstValue, numberOfNumbers, separator, step } =
|
type={'number'}
|
||||||
optionsValues;
|
/>
|
||||||
setResult(
|
<TextFieldWithDesc
|
||||||
listOfIntegers(
|
description={'Number of elements in sequence.'}
|
||||||
Number(firstValue),
|
value={values.numberOfNumbers}
|
||||||
Number(numberOfNumbers),
|
onOwnChange={(val) => updateField('numberOfNumbers', val)}
|
||||||
Number(step),
|
type={'number'}
|
||||||
separator
|
/>
|
||||||
)
|
</Box>
|
||||||
);
|
)
|
||||||
}}
|
},
|
||||||
initialValues={initialValues}
|
{
|
||||||
/>
|
title: 'Separator',
|
||||||
</Box>
|
component: (
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={
|
||||||
|
'Separate elements in the arithmetic sequence by this character.'
|
||||||
|
}
|
||||||
|
value={values.separator}
|
||||||
|
onOwnChange={(val) => updateField('separator', val)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
compute={compute}
|
||||||
|
resultComponent={
|
||||||
|
<ToolTextResult title={'Generated numbers'} value={result} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,8 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions, { GetGroupsType } from '@components/options/ToolOptions';
|
|
||||||
import SimpleRadio from '@components/options/SimpleRadio';
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import ToolExamples, {
|
import ToolExamples, {
|
||||||
CardExampleType
|
CardExampleType
|
||||||
} from '@components/examples/ToolExamples';
|
} from '@components/examples/ToolExamples';
|
||||||
@@ -16,6 +14,7 @@ import removeDuplicateLines, {
|
|||||||
DuplicateRemoverOptions,
|
DuplicateRemoverOptions,
|
||||||
NewlineOption
|
NewlineOption
|
||||||
} from './service';
|
} from './service';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
|
||||||
// Initial values for our form
|
// Initial values for our form
|
||||||
const initialValues: DuplicateRemoverOptions = {
|
const initialValues: DuplicateRemoverOptions = {
|
||||||
@@ -174,7 +173,6 @@ Elderberry`,
|
|||||||
export default function RemoveDuplicateLines({ title }: ToolComponentProps) {
|
export default function RemoveDuplicateLines({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const formRef = useRef<FormikProps<typeof initialValues>>(null);
|
|
||||||
|
|
||||||
const computeExternal = (
|
const computeExternal = (
|
||||||
optionsValues: typeof initialValues,
|
optionsValues: typeof initialValues,
|
||||||
@@ -183,78 +181,65 @@ export default function RemoveDuplicateLines({ title }: ToolComponentProps) {
|
|||||||
setResult(removeDuplicateLines(inputText, optionsValues));
|
setResult(removeDuplicateLines(inputText, optionsValues));
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGroups: GetGroupsType<typeof initialValues> = ({
|
|
||||||
values,
|
|
||||||
updateField
|
|
||||||
}) => [
|
|
||||||
{
|
|
||||||
title: 'Operation Mode',
|
|
||||||
component: operationModes.map(({ title, description, value }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={value}
|
|
||||||
checked={value === values.mode}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
onClick={() => updateField('mode', value)}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Newlines, Tabs and Spaces',
|
|
||||||
component: [
|
|
||||||
...newlineOptions.map(({ title, description, value }) => (
|
|
||||||
<SimpleRadio
|
|
||||||
key={value}
|
|
||||||
checked={value === values.newlines}
|
|
||||||
title={title}
|
|
||||||
description={description}
|
|
||||||
onClick={() => updateField('newlines', value)}
|
|
||||||
/>
|
|
||||||
)),
|
|
||||||
<CheckboxWithDesc
|
|
||||||
key="trimTextLines"
|
|
||||||
checked={values.trimTextLines}
|
|
||||||
title="Trim Text Lines"
|
|
||||||
description="Before filtering uniques, remove tabs and spaces from the beginning and end of all lines."
|
|
||||||
onChange={(checked) => updateField('trimTextLines', checked)}
|
|
||||||
/>
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Sort Lines',
|
|
||||||
component: [
|
|
||||||
<CheckboxWithDesc
|
|
||||||
key="sortLines"
|
|
||||||
checked={values.sortLines}
|
|
||||||
title="Sort the Output Lines"
|
|
||||||
description="After removing the duplicates, sort the unique lines."
|
|
||||||
onChange={(checked) => updateField('sortLines', checked)}
|
|
||||||
/>
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={<ToolTextInput value={input} onChange={setInput} />}
|
input={input}
|
||||||
result={
|
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
|
||||||
<ToolTextResult title={'Text without duplicates'} value={result} />
|
resultComponent={
|
||||||
|
<ToolTextResult title={'Text without duplicates'} value={result} />
|
||||||
|
}
|
||||||
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'Operation Mode',
|
||||||
|
component: operationModes.map(({ title, description, value }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={value}
|
||||||
|
checked={value === values.mode}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
onClick={() => updateField('mode', value)}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Newlines, Tabs and Spaces',
|
||||||
|
component: [
|
||||||
|
...newlineOptions.map(({ title, description, value }) => (
|
||||||
|
<SimpleRadio
|
||||||
|
key={value}
|
||||||
|
checked={value === values.newlines}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
onClick={() => updateField('newlines', value)}
|
||||||
|
/>
|
||||||
|
)),
|
||||||
|
<CheckboxWithDesc
|
||||||
|
key="trimTextLines"
|
||||||
|
checked={values.trimTextLines}
|
||||||
|
title="Trim Text Lines"
|
||||||
|
description="Before filtering uniques, remove tabs and spaces from the beginning and end of all lines."
|
||||||
|
onChange={(checked) => updateField('trimTextLines', checked)}
|
||||||
|
/>
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Sort Lines',
|
||||||
|
component: [
|
||||||
|
<CheckboxWithDesc
|
||||||
|
key="sortLines"
|
||||||
|
checked={values.sortLines}
|
||||||
|
title="Sort the Output Lines"
|
||||||
|
description="After removing the duplicates, sort the unique lines."
|
||||||
|
onChange={(checked) => updateField('sortLines', checked)}
|
||||||
|
/>
|
||||||
|
]
|
||||||
}
|
}
|
||||||
/>
|
]}
|
||||||
<ToolOptions
|
compute={computeExternal}
|
||||||
compute={computeExternal}
|
setInput={setInput}
|
||||||
getGroups={getGroups}
|
exampleCards={exampleCards}
|
||||||
initialValues={initialValues}
|
/>
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
<ToolExamples
|
|
||||||
title={title}
|
|
||||||
exampleCards={exampleCards}
|
|
||||||
getGroups={getGroups}
|
|
||||||
formRef={formRef}
|
|
||||||
setInput={setInput}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,15 @@ import { Box } from '@mui/material';
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import ToolTextInput from '@components/input/ToolTextInput';
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
import ToolTextResult from '@components/result/ToolTextResult';
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
import ToolOptions, { GetGroupsType } from '@components/options/ToolOptions';
|
|
||||||
import { compute, SplitOperatorType } from './service';
|
import { compute, SplitOperatorType } from './service';
|
||||||
import RadioWithTextField from '@components/options/RadioWithTextField';
|
import RadioWithTextField from '@components/options/RadioWithTextField';
|
||||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import ToolExamples, {
|
import ToolExamples, {
|
||||||
CardExampleType
|
CardExampleType
|
||||||
} from '@components/examples/ToolExamples';
|
} from '@components/examples/ToolExamples';
|
||||||
import { ToolComponentProps } from '@tools/defineTool';
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
import { FormikProps } from 'formik';
|
import { FormikProps } from 'formik';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||||
@@ -135,8 +134,11 @@ easy`,
|
|||||||
export default function SplitText({ title }: ToolComponentProps) {
|
export default function SplitText({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<string>('');
|
const [input, setInput] = useState<string>('');
|
||||||
const [result, setResult] = useState<string>('');
|
const [result, setResult] = useState<string>('');
|
||||||
const formRef = useRef<FormikProps<typeof initialValues>>(null);
|
|
||||||
const computeExternal = (optionsValues: typeof initialValues, input: any) => {
|
const computeExternal = (
|
||||||
|
optionsValues: typeof initialValues,
|
||||||
|
input: string
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
splitSeparatorType,
|
splitSeparatorType,
|
||||||
outputSeparator,
|
outputSeparator,
|
||||||
@@ -163,56 +165,44 @@ export default function SplitText({ title }: ToolComponentProps) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGroups: GetGroupsType<typeof initialValues> = ({
|
|
||||||
values,
|
|
||||||
updateField
|
|
||||||
}) => [
|
|
||||||
{
|
|
||||||
title: 'Split separator options',
|
|
||||||
component: splitOperators.map(({ title, description, type }) => (
|
|
||||||
<RadioWithTextField
|
|
||||||
key={type}
|
|
||||||
checked={type === values.splitSeparatorType}
|
|
||||||
title={title}
|
|
||||||
fieldName={'splitSeparatorType'}
|
|
||||||
description={description}
|
|
||||||
value={values[`${type}Value`]}
|
|
||||||
onRadioClick={() => updateField('splitSeparatorType', type)}
|
|
||||||
onTextChange={(val) => updateField(`${type}Value`, val)}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Output separator options',
|
|
||||||
component: outputOptions.map((option) => (
|
|
||||||
<TextFieldWithDesc
|
|
||||||
key={option.accessor}
|
|
||||||
value={values[option.accessor]}
|
|
||||||
onOwnChange={(value) => updateField(option.accessor, value)}
|
|
||||||
description={option.description}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={<ToolTextInput value={input} onChange={setInput} />}
|
input={input}
|
||||||
result={<ToolTextResult title={'Text pieces'} value={result} />}
|
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
|
||||||
/>
|
resultComponent={<ToolTextResult title={'Text pieces'} value={result} />}
|
||||||
<ToolOptions
|
initialValues={initialValues}
|
||||||
compute={computeExternal}
|
getGroups={({ values, updateField }) => [
|
||||||
getGroups={getGroups}
|
{
|
||||||
initialValues={initialValues}
|
title: 'Split separator options',
|
||||||
input={input}
|
component: splitOperators.map(({ title, description, type }) => (
|
||||||
/>
|
<RadioWithTextField
|
||||||
<ToolExamples
|
key={type}
|
||||||
title={title}
|
checked={type === values.splitSeparatorType}
|
||||||
exampleCards={exampleCards}
|
title={title}
|
||||||
getGroups={getGroups}
|
fieldName={'splitSeparatorType'}
|
||||||
formRef={formRef}
|
description={description}
|
||||||
setInput={setInput}
|
value={values[`${type}Value`]}
|
||||||
/>
|
onRadioClick={() => updateField('splitSeparatorType', type)}
|
||||||
</Box>
|
onTextChange={(val) => updateField(`${type}Value`, val)}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Output separator options',
|
||||||
|
component: outputOptions.map((option) => (
|
||||||
|
<TextFieldWithDesc
|
||||||
|
key={option.accessor}
|
||||||
|
value={values[option.accessor]}
|
||||||
|
onOwnChange={(value) => updateField(option.accessor, value)}
|
||||||
|
description={option.description}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
compute={computeExternal}
|
||||||
|
setInput={setInput}
|
||||||
|
exampleCards={exampleCards}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -3,12 +3,12 @@ import React, { useState } from 'react';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import ToolFileInput from '@components/input/ToolFileInput';
|
import ToolFileInput from '@components/input/ToolFileInput';
|
||||||
import ToolFileResult from '@components/result/ToolFileResult';
|
import ToolFileResult from '@components/result/ToolFileResult';
|
||||||
import ToolOptions from '@components/options/ToolOptions';
|
|
||||||
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
||||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { FrameOptions, GifReader, GifWriter } from 'omggif';
|
import { FrameOptions, GifReader, GifWriter } from 'omggif';
|
||||||
import { gifBinaryToFile } from '../../../../../utils/gif';
|
import { gifBinaryToFile } from '@utils/gif';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
newSpeed: 200
|
newSpeed: 200
|
||||||
@@ -16,11 +16,11 @@ const initialValues = {
|
|||||||
const validationSchema = Yup.object({
|
const validationSchema = Yup.object({
|
||||||
// splitSeparator: Yup.string().required('The separator is required')
|
// splitSeparator: Yup.string().required('The separator is required')
|
||||||
});
|
});
|
||||||
export default function ChangeSpeed() {
|
export default function ChangeSpeed({ title }: ToolComponentProps) {
|
||||||
const [input, setInput] = useState<File | null>(null);
|
const [input, setInput] = useState<File | null>(null);
|
||||||
const [result, setResult] = useState<File | null>(null);
|
const [result, setResult] = useState<File | null>(null);
|
||||||
|
|
||||||
const compute = (optionsValues: typeof initialValues, input: File) => {
|
const compute = (optionsValues: typeof initialValues, input: File | null) => {
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
const { newSpeed } = optionsValues;
|
const { newSpeed } = optionsValues;
|
||||||
|
|
||||||
@@ -104,45 +104,43 @@ export default function ChangeSpeed() {
|
|||||||
processImage(input, newSpeed);
|
processImage(input, newSpeed);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Box>
|
<ToolContent
|
||||||
<ToolInputAndResult
|
title={title}
|
||||||
input={
|
input={input}
|
||||||
<ToolFileInput
|
inputComponent={
|
||||||
value={input}
|
<ToolFileInput
|
||||||
onChange={setInput}
|
value={input}
|
||||||
accept={['image/gif']}
|
onChange={setInput}
|
||||||
title={'Input GIF'}
|
accept={['image/gif']}
|
||||||
/>
|
title={'Input GIF'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
resultComponent={
|
||||||
|
<ToolFileResult
|
||||||
|
title={'Output GIF with new speed'}
|
||||||
|
value={result}
|
||||||
|
extension={'gif'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
initialValues={initialValues}
|
||||||
|
getGroups={({ values, updateField }) => [
|
||||||
|
{
|
||||||
|
title: 'New GIF speed',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
value={values.newSpeed}
|
||||||
|
onOwnChange={(val) => updateField('newSpeed', Number(val))}
|
||||||
|
description={'Default new GIF speed.'}
|
||||||
|
InputProps={{ endAdornment: <Typography>ms</Typography> }}
|
||||||
|
type={'number'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result={
|
]}
|
||||||
<ToolFileResult
|
compute={compute}
|
||||||
title={'Output GIF with new speed'}
|
setInput={setInput}
|
||||||
value={result}
|
/>
|
||||||
extension={'gif'}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ToolOptions
|
|
||||||
compute={compute}
|
|
||||||
getGroups={({ values, updateField }) => [
|
|
||||||
{
|
|
||||||
title: 'New GIF speed',
|
|
||||||
component: (
|
|
||||||
<Box>
|
|
||||||
<TextFieldWithDesc
|
|
||||||
value={values.newSpeed}
|
|
||||||
onOwnChange={(val) => updateField('newSpeed', Number(val))}
|
|
||||||
description={'Default new GIF speed.'}
|
|
||||||
InputProps={{ endAdornment: <Typography>ms</Typography> }}
|
|
||||||
type={'number'}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
initialValues={initialValues}
|
|
||||||
input={input}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user