feat: json pretty

This commit is contained in:
Ibrahima G. Coulibaly
2025-02-27 13:05:38 +00:00
parent 18c305ac9b
commit d2eb7030d8
12 changed files with 78 additions and 49 deletions

47
.idea/workspace.xml generated
View File

@@ -4,13 +4,19 @@
<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="refact: examples"> <list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="fix: examples">
<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/ToolHeader.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolHeader.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/examples/Examples.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/examples/ToolExamples.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/scripts/create-tool.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/create-tool.mjs" 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/home/Categories.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/home/Categories.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/join/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/join/index.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/pages/tools/string/join/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/join/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/string/split/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/split/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/tools/defineTool.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/tools/defineTool.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/tools/defineTool.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/tools/defineTool.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/tools/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/tools/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/string.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/string.ts" 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" />
@@ -78,7 +84,7 @@
"Vitest.mergeText.executor": "Run", "Vitest.mergeText.executor": "Run",
"Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run", "Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
"Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run", "Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
"git-widget-placeholder": "examples", "git-widget-placeholder": "main",
"ignore.virus.scanning.warn.message": "true", "ignore.virus.scanning.warn.message": "true",
"kotlin-language-version-configured": "true", "kotlin-language-version-configured": "true",
"last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/src/assets", "last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/src/assets",
@@ -677,11 +683,38 @@
</option> </option>
</component> </component>
<component name="Vcs.Log.Tabs.Properties"> <component name="Vcs.Log.Tabs.Properties">
<option name="RECENT_FILTERS">
<map>
<entry key="Branch">
<value>
<list>
<RecentGroup>
<option name="FILTER_VALUES">
<option value="origin/examples" />
</option>
</RecentGroup>
</list>
</value>
</entry>
</map>
</option>
<option name="TAB_STATES"> <option name="TAB_STATES">
<map> <map>
<entry key="MAIN"> <entry key="MAIN">
<value> <value>
<State /> <State>
<option name="FILTERS">
<map>
<entry key="branch">
<value>
<list>
<option value="origin/examples" />
</list>
</value>
</entry>
</map>
</option>
</State>
</value> </value>
</entry> </entry>
</map> </map>
@@ -691,7 +724,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="chore: format number" />
<MESSAGE value="feat: rotate ui" /> <MESSAGE value="feat: rotate ui" />
<MESSAGE value="feat: shuffle ui" /> <MESSAGE value="feat: shuffle ui" />
<MESSAGE value="refactor: remove validation schema" /> <MESSAGE value="refactor: remove validation schema" />
@@ -716,7 +748,8 @@
<MESSAGE value="chore: handle enter press on search" /> <MESSAGE value="chore: handle enter press on search" />
<MESSAGE value="chore: show tooloptions in example" /> <MESSAGE value="chore: show tooloptions in example" />
<MESSAGE value="refact: examples" /> <MESSAGE value="refact: examples" />
<option name="LAST_COMMIT_MESSAGE" value="refact: examples" /> <MESSAGE value="fix: examples" />
<option name="LAST_COMMIT_MESSAGE" value="fix: examples" />
</component> </component>
<component name="XSLT-Support.FileAssociations.UIState"> <component name="XSLT-Support.FileAssociations.UIState">
<expand /> <expand />

16
package-lock.json generated
View File

@@ -10,8 +10,6 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.4", "@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5", "@emotion/styled": "^11.11.5",
"@hugeicons/core-free-icons": "^1.0.10",
"@hugeicons/react": "^1.0.3",
"@mui/icons-material": "^5.15.20", "@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20", "@mui/material": "^5.15.20",
"@playwright/test": "^1.45.0", "@playwright/test": "^1.45.0",
@@ -1402,20 +1400,6 @@
"@hapi/hoek": "^9.0.0" "@hapi/hoek": "^9.0.0"
} }
}, },
"node_modules/@hugeicons/core-free-icons": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/@hugeicons/core-free-icons/-/core-free-icons-1.0.10.tgz",
"integrity": "sha512-XMjwTffefQGJ0B3gjnS9IV2UqM5qYT4WUJjD+cD7x6TfwE8rSAb+foGNbcyCjpXKVOnuyaJa+y4ukrPyNY/DBw==",
"license": "MIT"
},
"node_modules/@hugeicons/react": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@hugeicons/react/-/react-1.0.3.tgz",
"integrity": "sha512-NJN8PmxTZlkt3T9a7uNZLhkJlIyQUt+sMxM5Qa/UH1qC1fBkwI7C7HSY/y4f7jjo5SQl7zRkm3hWH9tpWuHmWw==",
"peerDependencies": {
"react": ">=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.14", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",

View File

@@ -27,8 +27,6 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.4", "@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5", "@emotion/styled": "^11.11.5",
"@hugeicons/core-free-icons": "^1.0.10",
"@hugeicons/react": "^1.0.3",
"@mui/icons-material": "^5.15.20", "@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20", "@mui/material": "^5.15.20",
"@playwright/test": "^1.45.0", "@playwright/test": "^1.45.0",

View File

@@ -79,6 +79,7 @@ import React from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
const initialValues = {}; const initialValues = {};
type InitialValuesType = typeof 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')
}); });

View File

@@ -17,7 +17,7 @@ export interface ExampleCardProps<T> {
sampleText: string; sampleText: string;
sampleResult: string; sampleResult: string;
sampleOptions: T; sampleOptions: T;
changeInputResult: (newOptions: T) => void; changeInputResult: (newInput: string, newOptions: T) => void;
getGroups: GetGroupsType<T>; getGroups: GetGroupsType<T>;
} }
@@ -35,7 +35,7 @@ export default function ExampleCard<T>({
<Card <Card
raised raised
onClick={() => { onClick={() => {
changeInputResult(sampleOptions); changeInputResult(sampleText, sampleOptions);
}} }}
sx={{ sx={{
bgcolor: theme.palette.background.default, bgcolor: theme.palette.background.default,

View File

@@ -15,6 +15,7 @@ export interface ExampleProps<T> {
exampleCards: CardExampleType<T>[]; exampleCards: CardExampleType<T>[];
getGroups: GetGroupsType<T>; getGroups: GetGroupsType<T>;
formRef: React.RefObject<FormikProps<T>>; formRef: React.RefObject<FormikProps<T>>;
setInput: React.Dispatch<React.SetStateAction<string>>;
} }
export default function ToolExamples<T>({ export default function ToolExamples<T>({
@@ -22,9 +23,11 @@ export default function ToolExamples<T>({
subtitle, subtitle,
exampleCards, exampleCards,
getGroups, getGroups,
formRef formRef,
setInput
}: ExampleProps<T>) { }: ExampleProps<T>) {
function changeInputResult(newOptions: T) { function changeInputResult(newInput: string, newOptions: T) {
setInput(newInput);
formRef.current?.setValues(newOptions); formRef.current?.setValues(newOptions);
const toolsElement = document.getElementById('tool'); const toolsElement = document.getElementById('tool');
if (toolsElement) { if (toolsElement) {

View File

@@ -1,12 +1,12 @@
import { getToolsByCategory } from '@tools/index'; import { getToolsByCategory } from '@tools/index';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import { Card, CardContent, Stack } from '@mui/material'; import { Card, CardContent, Stack } from '@mui/material';
import { HugeiconsIcon } from '@hugeicons/react';
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import { useState } from 'react'; import { useState } from 'react';
import { categoriesColors } from 'config/uiConfig'; import { categoriesColors } from 'config/uiConfig';
import { Icon } from '@iconify/react';
type ArrayElement<ArrayType extends readonly unknown[]> = type ArrayElement<ArrayType extends readonly unknown[]> =
ArrayType extends readonly (infer ElementType)[] ? ElementType : never; ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
@@ -20,7 +20,6 @@ const SingleCategory = function ({
}) { }) {
const navigate = useNavigate(); const navigate = useNavigate();
const [hovered, setHovered] = useState<boolean>(false); const [hovered, setHovered] = useState<boolean>(false);
const Icon = category.icon;
const toggleHover = () => setHovered((prevState) => !prevState); const toggleHover = () => setHovered((prevState) => !prevState);
return ( return (
<Grid <Grid
@@ -38,8 +37,9 @@ const SingleCategory = function ({
> >
<CardContent> <CardContent>
<Stack direction={'row'} spacing={2} alignItems={'center'}> <Stack direction={'row'} spacing={2} alignItems={'center'}>
<HugeiconsIcon <Icon
icon={Icon} icon={category.icon}
fontSize={'60px'}
style={{ style={{
transform: `scale(${hovered ? 1.1 : 1}` transform: `scale(${hovered ? 1.1 : 1}`
}} }}

View File

@@ -179,6 +179,7 @@ export default function JoinText({ title }: ToolComponentProps) {
exampleCards={exampleCards} exampleCards={exampleCards}
getGroups={getGroups} getGroups={getGroups}
formRef={formRef} formRef={formRef}
setInput={setInput}
/> />
</Box> </Box>
); );

View File

@@ -211,6 +211,7 @@ export default function SplitText({ title }: ToolComponentProps) {
exampleCards={exampleCards} exampleCards={exampleCards}
getGroups={getGroups} getGroups={getGroups}
formRef={formRef} formRef={formRef}
setInput={setInput}
/> />
</Box> </Box>
); );

View File

@@ -12,7 +12,13 @@ interface ToolOptions {
shortDescription: string; shortDescription: string;
} }
export type ToolCategory = 'string' | 'png' | 'number' | 'gif' | 'list'; export type ToolCategory =
| 'string'
| 'png'
| 'number'
| 'gif'
| 'list'
| 'json';
export interface DefinedTool { export interface DefinedTool {
type: ToolCategory; type: ToolCategory;

View File

@@ -6,18 +6,13 @@ import { numberTools } from '../pages/tools/number';
import { videoTools } from '../pages/tools/video'; import { videoTools } from '../pages/tools/video';
import { listTools } from '../pages/tools/list'; import { listTools } from '../pages/tools/list';
import { Entries } from 'type-fest'; import { Entries } from 'type-fest';
import { import { jsonTools } from '../pages/tools/json';
ArrangeByNumbers19Icon, import { IconifyIcon } from '@iconify/react';
Gif01Icon,
HugeiconsIcon,
LeftToRightListBulletIcon,
Png01Icon,
TextIcon
} from '@hugeicons/core-free-icons';
export const tools: DefinedTool[] = [ export const tools: DefinedTool[] = [
...imageTools, ...imageTools,
...stringTools, ...stringTools,
...jsonTools,
...listTools, ...listTools,
...videoTools, ...videoTools,
...numberTools ...numberTools
@@ -26,38 +21,44 @@ const categoriesConfig: {
type: ToolCategory; type: ToolCategory;
value: string; value: string;
title?: string; title?: string;
icon: typeof HugeiconsIcon; icon: IconifyIcon | string;
}[] = [ }[] = [
{ {
type: 'string', type: 'string',
title: 'Text', title: 'Text',
icon: TextIcon, icon: 'solar:text-bold-duotone',
value: value:
'Tools for working with text convert text to images, find and replace text, split text into fragments, join text lines, repeat text, and much more.' 'Tools for working with text convert text to images, find and replace text, split text into fragments, join text lines, repeat text, and much more.'
}, },
{ {
type: 'png', type: 'png',
icon: Png01Icon, icon: 'ph:file-png-thin',
value: value:
'Tools for working with PNG images convert PNGs to JPGs, create transparent PNGs, change PNG colors, crop, rotate, resize PNGs, and much more.' 'Tools for working with PNG images convert PNGs to JPGs, create transparent PNGs, change PNG colors, crop, rotate, resize PNGs, and much more.'
}, },
{ {
type: 'number', type: 'number',
icon: ArrangeByNumbers19Icon, icon: 'lsicon:number-filled',
value: value:
'Tools for working with numbers generate number sequences, convert numbers to words and words to numbers, sort, round, factor numbers, and much more.' 'Tools for working with numbers generate number sequences, convert numbers to words and words to numbers, sort, round, factor numbers, and much more.'
}, },
{ {
type: 'gif', type: 'gif',
icon: Gif01Icon, icon: 'material-symbols-light:gif-rounded',
value: value:
'Tools for working with GIF animations create transparent GIFs, extract GIF frames, add text to GIF, crop, rotate, reverse GIFs, and much more.' 'Tools for working with GIF animations create transparent GIFs, extract GIF frames, add text to GIF, crop, rotate, reverse GIFs, and much more.'
}, },
{ {
type: 'list', type: 'list',
icon: LeftToRightListBulletIcon, icon: 'solar:list-bold-duotone',
value: value:
'Tools for working with lists sort, reverse, randomize lists, find unique and duplicate list items, change list item separators, and much more.' 'Tools for working with lists sort, reverse, randomize lists, find unique and duplicate list items, change list item separators, and much more.'
},
{
type: 'json',
icon: 'lets-icons:json-light',
value:
'Tools for working with JSON data structures prettify and minify JSON objects, flatten JSON arrays, stringify JSON values, analyze data, and much more'
} }
]; ];
export const filterTools = ( export const filterTools = (
@@ -82,7 +83,7 @@ export const filterTools = (
export const getToolsByCategory = (): { export const getToolsByCategory = (): {
title: string; title: string;
description: string; description: string;
icon: typeof HugeiconsIcon; icon: IconifyIcon | string;
type: string; type: string;
example: { title: string; path: string }; example: { title: string; path: string };
tools: DefinedTool[]; tools: DefinedTool[];

View File

@@ -9,6 +9,7 @@ export function isNumber(number: any) {
export const replaceSpecialCharacters = (str: string) => { export const replaceSpecialCharacters = (str: string) => {
return str return str
.replace(/\\"/g, '"')
.replace(/\\n/g, '\n') .replace(/\\n/g, '\n')
.replace(/\\t/g, '\t') .replace(/\\t/g, '\t')
.replace(/\\r/g, '\r') .replace(/\\r/g, '\r')