mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-12-29 16:16:02 +00:00
chore: use monaco editor
This commit is contained in:
@@ -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<HTMLInputElement>(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<HTMLInputElement>) => {
|
||||
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 (
|
||||
<Box>
|
||||
<InputHeader title={title || t('toolTextInput.input')} />
|
||||
<LineNumberWrapper>
|
||||
<pre className="line-numbers">{lineNumbers}</pre>
|
||||
<TextField
|
||||
value={value}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
fullWidth
|
||||
multiline
|
||||
rows={10}
|
||||
placeholder={placeholder || t('toolTextInput.placeholder')}
|
||||
sx={{
|
||||
'&.MuiTextField-root': {
|
||||
backgroundColor: 'background.paper'
|
||||
}
|
||||
}}
|
||||
inputProps={{
|
||||
'data-testid': 'text-input'
|
||||
}}
|
||||
/>
|
||||
</LineNumberWrapper>
|
||||
<InputFooter handleCopy={handleCopy} handleImport={handleImportClick} />
|
||||
<input
|
||||
type="file"
|
||||
accept="*"
|
||||
ref={fileInputRef}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
73
src/components/input/ToolCodeInput.tsx
Normal file
73
src/components/input/ToolCodeInput.tsx
Normal file
@@ -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<HTMLInputElement>(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<HTMLInputElement>) => {
|
||||
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 (
|
||||
<Box>
|
||||
<InputHeader title={title || t('toolTextInput.input')} />
|
||||
<Box height={globalInputHeight}>
|
||||
<Editor
|
||||
height={'87%'}
|
||||
language={language}
|
||||
value={value}
|
||||
onChange={(value) => onChange(value ?? '')}
|
||||
/>
|
||||
<InputFooter handleCopy={handleCopy} handleImport={handleImportClick} />
|
||||
<input
|
||||
type="file"
|
||||
accept="*"
|
||||
ref={fileInputRef}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -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={
|
||||
<StyledContainer>
|
||||
<StyledGrid container spacing={2}>
|
||||
<Grid item xs={4}>
|
||||
<StyledInputWrapper>
|
||||
<LineNumberInput
|
||||
title="First JSON"
|
||||
value={input1}
|
||||
onChange={handleInput1Change}
|
||||
placeholder="Paste your first JSON here..."
|
||||
/>
|
||||
</StyledInputWrapper>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<StyledInputWrapper>
|
||||
<LineNumberInput
|
||||
title="Second JSON"
|
||||
value={input2}
|
||||
onChange={handleInput2Change}
|
||||
placeholder="Paste your second JSON here..."
|
||||
/>
|
||||
</StyledInputWrapper>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<StyledInputWrapper>
|
||||
<ToolTextResult
|
||||
title="Differences"
|
||||
value={result}
|
||||
extension={'txt'}
|
||||
/>
|
||||
</StyledInputWrapper>
|
||||
</Grid>
|
||||
</StyledGrid>
|
||||
</StyledContainer>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<ToolCodeInput
|
||||
title="First JSON"
|
||||
value={input1}
|
||||
onChange={handleInput1Change}
|
||||
language={'json'}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<ToolCodeInput
|
||||
title="Second JSON"
|
||||
language={'json'}
|
||||
value={input2}
|
||||
onChange={handleInput2Change}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} lg={4}>
|
||||
<ToolTextResult
|
||||
title="Differences"
|
||||
value={result}
|
||||
extension={'txt'}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user