diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 7c01f00..fdef5fc 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,17 +4,24 @@
-
+
+
-
+
-
+
+
+
+
+
+
@@ -272,7 +279,7 @@
"Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp.executor": "Run",
"Vitest.replaceText function.executor": "Run",
"Vitest.timeBetweenDates.executor": "Run",
- "git-widget-placeholder": "#190 on fork/AshAnand34/en-hi-translation",
+ "git-widget-placeholder": "#197 on fork/bhavesh158/json-compare",
"ignore.virus.scanning.warn.message": "true",
"kotlin-language-version-configured": "true",
"last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools",
@@ -519,14 +526,6 @@
-
-
- 1743644942488
-
-
-
- 1743644942488
-
1743645074051
@@ -911,7 +910,15 @@
1752515675314
-
+
+
+ 1752803825523
+
+
+
+ 1752803825523
+
+
@@ -958,7 +965,6 @@
-
@@ -983,7 +989,8 @@
-
+
+
false
diff --git a/package-lock.json b/package-lock.json
index cc72c78..835edf1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"@ffmpeg/util": "^0.12.2",
"@imgly/background-removal": "^1.6.0",
"@jimp/types": "^1.6.0",
+ "@monaco-editor/react": "^4.7.0",
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@playwright/test": "^1.45.0",
@@ -2104,6 +2105,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@monaco-editor/loader": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.5.0.tgz",
+ "integrity": "sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==",
+ "license": "MIT",
+ "dependencies": {
+ "state-local": "^1.0.6"
+ }
+ },
+ "node_modules/@monaco-editor/react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz",
+ "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@monaco-editor/loader": "^1.5.0"
+ },
+ "peerDependencies": {
+ "monaco-editor": ">= 0.25.0 < 1",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/@mui/base": {
"version": "5.0.0-beta.40",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz",
@@ -8902,6 +8926,13 @@
"ufo": "^1.5.3"
}
},
+ "node_modules/monaco-editor": {
+ "version": "0.52.2",
+ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
+ "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/morsee": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/morsee/-/morsee-1.0.9.tgz",
@@ -11271,6 +11302,12 @@
"node": ">=6"
}
},
+ "node_modules/state-local": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
+ "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==",
+ "license": "MIT"
+ },
"node_modules/std-env": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz",
diff --git a/package.json b/package.json
index 32edb2d..d0d1137 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"@ffmpeg/util": "^0.12.2",
"@imgly/background-removal": "^1.6.0",
"@jimp/types": "^1.6.0",
+ "@monaco-editor/react": "^4.7.0",
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@playwright/test": "^1.45.0",
diff --git a/src/components/input/LineNumberInput.tsx b/src/components/input/LineNumberInput.tsx
deleted file mode 100644
index 7adc33e..0000000
--- a/src/components/input/LineNumberInput.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-import { Box, styled, TextField } from '@mui/material';
-import React, { useContext, useRef } from 'react';
-import { CustomSnackBarContext } from '../../contexts/CustomSnackBarContext';
-import InputHeader from '../InputHeader';
-import InputFooter from './InputFooter';
-import { useTranslation } from 'react-i18next';
-
-const LineNumberWrapper = styled(Box)(({ theme }) => ({
- position: 'relative',
- display: 'flex',
- backgroundColor: theme.palette.background.paper,
- '.line-numbers': {
- whiteSpace: 'pre',
- position: 'absolute',
- left: 0,
- top: 0,
- bottom: 0,
- width: '40px',
- backgroundColor: theme.palette.action.hover,
- borderRight: `1px solid ${theme.palette.divider}`,
- textAlign: 'right',
- paddingRight: '8px',
- paddingTop: '16px', // Align with TextField content
- paddingBottom: '8px',
- color: theme.palette.text.secondary,
- userSelect: 'none',
- fontSize: '14px',
- lineHeight: '1.5em',
- fontFamily: 'monospace',
- zIndex: 1,
- overflow: 'hidden'
- },
- '.MuiTextField-root': {
- position: 'relative',
- '& .MuiInputBase-root': {
- paddingLeft: '48px',
- fontFamily: 'monospace',
- fontSize: '14px',
- lineHeight: '1.5em'
- },
- '& .MuiInputBase-input': {
- lineHeight: '1.5em'
- }
- }
-}));
-
-export default function LineNumberInput({
- value,
- onChange,
- title = 'Input text',
- placeholder
-}: {
- title?: string;
- value: string;
- onChange: (value: string) => void;
- placeholder?: string;
-}) {
- const { t } = useTranslation();
- const { showSnackBar } = useContext(CustomSnackBarContext);
- const fileInputRef = useRef(null);
-
- const handleCopy = () => {
- navigator.clipboard
- .writeText(value)
- .then(() => showSnackBar(t('toolTextInput.copied'), 'success'))
- .catch((err) => {
- showSnackBar(t('toolTextInput.copyFailed', { error: err }), 'error');
- });
- };
-
- const handleFileChange = (event: React.ChangeEvent) => {
- const file = event.target.files?.[0];
- if (file) {
- const reader = new FileReader();
- reader.onload = (e) => {
- const text = e.target?.result;
- if (typeof text === 'string') {
- onChange(text);
- }
- };
- reader.readAsText(file);
- }
- };
-
- const handleImportClick = () => {
- fileInputRef.current?.click();
- };
-
- // Generate line numbers based on the content
- const lineCount = value.split('\n').length;
- const lineNumbers = Array.from({ length: lineCount }, (_, i) => i + 1).join(
- '\n'
- );
-
- return (
-
-
-
- {lineNumbers}
- onChange(event.target.value)}
- fullWidth
- multiline
- rows={10}
- placeholder={placeholder || t('toolTextInput.placeholder')}
- sx={{
- '&.MuiTextField-root': {
- backgroundColor: 'background.paper'
- }
- }}
- inputProps={{
- 'data-testid': 'text-input'
- }}
- />
-
-
-
-
- );
-}
diff --git a/src/components/input/ToolCodeInput.tsx b/src/components/input/ToolCodeInput.tsx
new file mode 100644
index 0000000..fd6df78
--- /dev/null
+++ b/src/components/input/ToolCodeInput.tsx
@@ -0,0 +1,73 @@
+import { Box } from '@mui/material';
+import React, { useContext, useRef } from 'react';
+import { CustomSnackBarContext } from '../../contexts/CustomSnackBarContext';
+import InputHeader from '../InputHeader';
+import InputFooter from './InputFooter';
+import { useTranslation } from 'react-i18next';
+import Editor from '@monaco-editor/react';
+import { globalInputHeight } from '../../config/uiConfig';
+
+export default function ToolCodeInput({
+ value,
+ onChange,
+ title = 'Input text',
+ language
+}: {
+ title?: string;
+ value: string;
+ language: string;
+ onChange: (value: string) => void;
+}) {
+ const { t } = useTranslation();
+ const { showSnackBar } = useContext(CustomSnackBarContext);
+ const fileInputRef = useRef(null);
+
+ const handleCopy = () => {
+ navigator.clipboard
+ .writeText(value)
+ .then(() => showSnackBar(t('toolTextInput.copied'), 'success'))
+ .catch((err) => {
+ showSnackBar(t('toolTextInput.copyFailed', { error: err }), 'error');
+ });
+ };
+
+ const handleFileChange = (event: React.ChangeEvent) => {
+ const file = event.target.files?.[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const text = e.target?.result;
+ if (typeof text === 'string') {
+ onChange(text);
+ }
+ };
+ reader.readAsText(file);
+ }
+ };
+
+ const handleImportClick = () => {
+ fileInputRef.current?.click();
+ };
+
+ return (
+
+
+
+ onChange(value ?? '')}
+ />
+
+
+
+
+ );
+}
diff --git a/src/pages/tools/json/json-comparison/index.tsx b/src/pages/tools/json/json-comparison/index.tsx
index c3b4878..28a78ea 100644
--- a/src/pages/tools/json/json-comparison/index.tsx
+++ b/src/pages/tools/json/json-comparison/index.tsx
@@ -1,42 +1,10 @@
-import { useState, useEffect } from 'react';
+import { useEffect, useState } from 'react';
import ToolContent from '@components/ToolContent';
-import LineNumberInput from '@components/input/LineNumberInput';
+import ToolCodeInput from '@components/input/ToolCodeInput';
import ToolTextResult from '@components/result/ToolTextResult';
import { compareJson } from './service';
import { ToolComponentProps } from '@tools/defineTool';
-import { Box, Grid, styled } from '@mui/material';
-
-const StyledContainer = styled(Box)({
- position: 'relative',
- width: '100%',
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- minHeight: '500px',
- marginBottom: '20px'
-});
-
-const StyledGrid = styled(Grid)({
- flex: 1,
- '& .MuiGrid-item': {
- height: '100%'
- }
-});
-
-const StyledInputWrapper = styled(Box)({
- height: '100%',
- '& > div': {
- height: '100%',
- '& textarea': {
- height: '100% !important',
- minHeight: '450px',
- resize: 'none',
- fontSize: '14px',
- lineHeight: '1.5',
- padding: '12px'
- }
- }
-});
+import { Grid } from '@mui/material';
type InitialValuesType = {};
@@ -73,8 +41,8 @@ export default function JsonComparison({ title }: ToolComponentProps) {
compareInputs();
}, [input1, input2]);
- const handleInput1Change = (value: string) => {
- setInput1(value);
+ const handleInput1Change = (value: string | undefined) => {
+ setInput1(value ?? '');
};
const handleInput2Change = (value: string) => {
@@ -90,39 +58,31 @@ export default function JsonComparison({ title }: ToolComponentProps) {
getGroups={null}
compute={() => {}}
inputComponent={
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
}
/>
);