mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-25 17:09:33 +02:00
Merge remote-tracking branch 'origin/string-join'
# Conflicts: # .idea/workspace.xml # src/tools/defineTool.tsx
This commit is contained in:
@@ -1,45 +1,14 @@
|
||||
import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
Card,
|
||||
CardContent,
|
||||
Stack,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
import { Box, Card, CardContent, Stack } from '@mui/material';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { filterTools, getToolsByCategory, tools } from '../../tools';
|
||||
import { useState } from 'react';
|
||||
import { DefinedTool } from '@tools/defineTool';
|
||||
import { getToolsByCategory } from '../../tools';
|
||||
import Button from '@mui/material/Button';
|
||||
import Hero from 'components/Hero';
|
||||
|
||||
const exampleTools: { label: string; url: string }[] = [
|
||||
{
|
||||
label: 'Create a transparent image',
|
||||
url: '/png/create-transparent'
|
||||
},
|
||||
{ label: 'Convert text to morse code', url: '/string/to-morse' },
|
||||
{ label: 'Change GIF speed', url: '' },
|
||||
{ label: 'Pick a random item', url: '' },
|
||||
{ label: 'Find and replace text', url: '' },
|
||||
{ label: 'Convert emoji to image', url: '' },
|
||||
{ label: 'Split a string', url: '/string/split' },
|
||||
{ label: 'Calculate number sum', url: '/number/sum' },
|
||||
{ label: 'Pixelate an image', url: '' }
|
||||
];
|
||||
export default function Home() {
|
||||
const navigate = useNavigate();
|
||||
const [inputValue, setInputValue] = useState<string>('');
|
||||
const [filteredTools, setFilteredTools] = useState<DefinedTool[]>(tools);
|
||||
const handleInputChange = (
|
||||
event: React.ChangeEvent<{}>,
|
||||
newInputValue: string
|
||||
) => {
|
||||
setInputValue(newInputValue);
|
||||
setFilteredTools(filterTools(tools, newInputValue));
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
padding={5}
|
||||
@@ -49,108 +18,38 @@ export default function Home() {
|
||||
justifyContent={'center'}
|
||||
width={'100%'}
|
||||
>
|
||||
<Box width={'60%'}>
|
||||
<Stack mb={1} direction={'row'} spacing={1}>
|
||||
<Typography fontSize={30}>Transform Your Workflow with </Typography>
|
||||
<Typography fontSize={30} color={'primary'}>
|
||||
Omni Tools
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Typography fontSize={20} mb={2}>
|
||||
Boost your productivity with Omni Tools, the ultimate toolkit for
|
||||
getting things done quickly! Access thousands of user-friendly
|
||||
utilities for editing images, text, lists, and data, all directly from
|
||||
your browser.
|
||||
</Typography>
|
||||
|
||||
<Autocomplete
|
||||
sx={{ mb: 2 }}
|
||||
autoHighlight
|
||||
options={filteredTools}
|
||||
getOptionLabel={(option) => option.name}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
fullWidth
|
||||
placeholder={'Search all tools'}
|
||||
sx={{ borderRadius: 2 }}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: <SearchIcon />
|
||||
}}
|
||||
onChange={(event) => handleInputChange(event, event.target.value)}
|
||||
/>
|
||||
)}
|
||||
renderOption={(props, option) => (
|
||||
<Box
|
||||
component="li"
|
||||
{...props}
|
||||
onClick={() => navigate(option.path)}
|
||||
>
|
||||
<Box>
|
||||
<Typography fontWeight={'bold'}>{option.name}</Typography>
|
||||
<Typography fontSize={12}>{option.description}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
<Grid container spacing={2} mt={2}>
|
||||
{exampleTools.map((tool) => (
|
||||
<Grid
|
||||
onClick={() => navigate(tool.url)}
|
||||
item
|
||||
xs={4}
|
||||
key={tool.label}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
padding: 1,
|
||||
borderRadius: 3,
|
||||
borderColor: 'grey',
|
||||
borderStyle: 'solid',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<Typography>{tool.label}</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
<Grid container mt={2} spacing={2}>
|
||||
{getToolsByCategory().map((category) => (
|
||||
<Grid key={category.type} item xs={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Link
|
||||
style={{ fontSize: 20 }}
|
||||
to={'/categories/' + category.type}
|
||||
>
|
||||
{category.title}
|
||||
</Link>
|
||||
<Typography sx={{ mt: 2 }}>{category.description}</Typography>
|
||||
<Stack
|
||||
mt={2}
|
||||
direction={'row'}
|
||||
justifyContent={'space-between'}
|
||||
>
|
||||
<Button
|
||||
variant={'contained'}
|
||||
>{`See all ${category.title}`}</Button>
|
||||
<Button
|
||||
onClick={() => navigate(category.example.path)}
|
||||
variant={'outlined'}
|
||||
>{`Try ${category.example.title}`}</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
<Hero />
|
||||
<Grid width={'80%'} container mt={2} spacing={2}>
|
||||
{getToolsByCategory().map((category) => (
|
||||
<Grid key={category.type} item xs={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Link
|
||||
style={{ fontSize: 20 }}
|
||||
to={'/categories/' + category.type}
|
||||
>
|
||||
{category.title}
|
||||
</Link>
|
||||
<Typography sx={{ mt: 2 }}>{category.description}</Typography>
|
||||
<Stack
|
||||
mt={2}
|
||||
direction={'row'}
|
||||
justifyContent={'space-between'}
|
||||
>
|
||||
<Button
|
||||
onClick={() => navigate('/categories/' + category.type)}
|
||||
variant={'contained'}
|
||||
>{`See all ${category.title}`}</Button>
|
||||
<Button
|
||||
onClick={() => navigate(category.example.path)}
|
||||
variant={'outlined'}
|
||||
>{`Try ${category.example.title}`}</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ export const tool = defineTool('png', {
|
||||
image,
|
||||
description:
|
||||
"World's simplest online Portable Network Graphics (PNG) color changer. Just import your PNG image in the editor on the left, select which colors to change, and you'll instantly get a new PNG with the new colors on the right. Free, quick, and very powerful. Import a PNG – replace its colors.",
|
||||
shortDescription: 'Quickly swap colors in a PNG image',
|
||||
keywords: ['change', 'colors', 'in', 'png'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
@@ -6,6 +6,7 @@ export const tool = defineTool('png', {
|
||||
name: 'Create transparent PNG',
|
||||
path: 'create-transparent',
|
||||
image,
|
||||
shortDescription: 'Quickly make a PNG image transparent',
|
||||
description:
|
||||
"World's simplest online Portable Network Graphics transparency maker. Just import your PNG image in the editor on the left and you will instantly get a transparent PNG on the right. Free, quick, and very powerful. Import a PNG – get a transparent PNG.",
|
||||
keywords: ['create', 'transparent'],
|
||||
|
@@ -8,6 +8,7 @@ export const tool = defineTool('number', {
|
||||
// image,
|
||||
description:
|
||||
'Quickly calculate the sum of numbers in your browser. To get your sum, just enter your list of numbers in the input field, adjust the separator between the numbers in the options below, and this utility will add up all these numbers.',
|
||||
shortDescription: 'Quickly sum numbers',
|
||||
keywords: ['sum'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
19
src/pages/string/join/Info.tsx
Normal file
19
src/pages/string/join/Info.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Box, Stack, Typography } from '@mui/material';
|
||||
|
||||
interface ExampleProps {
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export default function Example({ title, description }: ExampleProps) {
|
||||
return (
|
||||
<Stack direction={'row'} alignItems={'center'} spacing={2} mt={4}>
|
||||
<Box>
|
||||
<Typography mb={2} fontSize={30} color={'primary'}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography fontSize={20}>{description}</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
@@ -12,6 +12,11 @@ import CheckboxWithDesc from '../../../components/options/CheckboxWithDesc';
|
||||
import ToolOptionGroups from '../../../components/options/ToolOptionGroups';
|
||||
import ToolInputAndResult from '../../../components/ToolInputAndResult';
|
||||
|
||||
import Info from './Info';
|
||||
import Separator from '../../../tools/Separator';
|
||||
import AllTools from '../../../components/allTools/AllTools';
|
||||
import Examples from '../../../components/examples/Examples';
|
||||
|
||||
const initialValues = {
|
||||
joinCharacter: '',
|
||||
deleteBlank: true,
|
||||
@@ -48,6 +53,66 @@ const blankTrailingOptions: {
|
||||
}
|
||||
];
|
||||
|
||||
const exampleCards = [
|
||||
{
|
||||
title: 'Merge a To-Do List',
|
||||
description:
|
||||
"In this example, we merge a bullet point list into one sentence, separating each item by the word 'and'. We also remove all empty lines and trailing spaces. If we didn't remove the empty lines, then they'd be joined with the separator word, making the separator word appear multiple times. If we didn't remove the trailing tabs and spaces, then they'd create extra spacing in the joined text and it wouldn't look nice.",
|
||||
sampleText: `clean the house
|
||||
|
||||
go shopping
|
||||
feed the cat
|
||||
|
||||
make dinner
|
||||
build a rocket ship and fly away`,
|
||||
sampleResult: `clean the house and go shopping and feed the cat and make dinner and build a rocket ship and fly away`,
|
||||
requiredOptions: {
|
||||
joinCharacter: 'and',
|
||||
deleteBlankLines: true,
|
||||
deleteTrailingSpaces: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Comma Separated List',
|
||||
description:
|
||||
'This example joins a column of words into a comma separated list of words.',
|
||||
sampleText: `computer
|
||||
memory
|
||||
processor
|
||||
mouse
|
||||
keyboard`,
|
||||
sampleResult: `computer, memory, processor, mouse, keyboard`,
|
||||
requiredOptions: {
|
||||
joinCharacter: ',',
|
||||
deleteBlankLines: false,
|
||||
deleteTrailingSpaces: false
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Vertical Word to Horizontal',
|
||||
description:
|
||||
'This example rotates words from a vertical position to horizontal. An empty separator is used for this purpose.',
|
||||
sampleText: `T
|
||||
e
|
||||
x
|
||||
t
|
||||
a
|
||||
b
|
||||
u
|
||||
l
|
||||
o
|
||||
u
|
||||
s
|
||||
!`,
|
||||
sampleResult: `Textabulous!`,
|
||||
requiredOptions: {
|
||||
joinCharacter: '',
|
||||
deleteBlankLines: false,
|
||||
deleteTrailingSpaces: false
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default function JoinText() {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const { showSnackBar } = useContext(CustomSnackBarContext);
|
||||
@@ -69,6 +134,16 @@ export default function JoinText() {
|
||||
return null;
|
||||
};
|
||||
|
||||
function changeInputResult(input: string, result: string) {
|
||||
setInput(input);
|
||||
setResult(result);
|
||||
|
||||
const toolsElement = document.getElementById('tool');
|
||||
if (toolsElement) {
|
||||
toolsElement.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<ToolInputAndResult
|
||||
@@ -125,6 +200,19 @@ export default function JoinText() {
|
||||
)}
|
||||
</Formik>
|
||||
</ToolOptions>
|
||||
<Info
|
||||
title="What Is a Text Joiner?"
|
||||
description="With this tool you can join parts of the text together. It takes a list of text values, separated by newlines, and merges them together. You can set the character that will be placed between the parts of the combined text. Also, you can ignore all empty lines and remove spaces and tabs at the end of all lines. Textabulous!"
|
||||
/>
|
||||
<Separator backgroundColor="#5581b5" margin="50px" />
|
||||
<Examples
|
||||
title="Text Joiner Examples"
|
||||
subtitle="Click to try!"
|
||||
exampleCards={exampleCards.map((card) => ({
|
||||
...card,
|
||||
changeInputResult
|
||||
}))}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ export const tool = defineTool('string', {
|
||||
image,
|
||||
description:
|
||||
"World's Simplest Text Tool World's simplest browser-based utility for joining text. Load your text in the input form on the left and you'll automatically get merged text on the right. Powerful, free, and fast. Load text – get joined lines",
|
||||
shortDescription: 'Quickly merge texts',
|
||||
keywords: ['text', 'join'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
@@ -8,6 +8,7 @@ export const tool = defineTool('string', {
|
||||
image,
|
||||
description:
|
||||
"World's simplest browser-based utility for splitting text. Load your text in the input form on the left and you'll automatically get pieces of this text on the right. Powerful, free, and fast. Load text – get chunks.",
|
||||
shortDescription: 'Quickly split a text',
|
||||
keywords: ['text', 'split'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
@@ -8,6 +8,7 @@ export const tool = defineTool('string', {
|
||||
// image,
|
||||
description:
|
||||
"World's simplest browser-based utility for converting text to Morse code. Load your text in the input form on the left and you'll instantly get Morse code in the output area. Powerful, free, and fast. Load text – get Morse code.",
|
||||
shortDescription: 'Quickly encode text to morse',
|
||||
keywords: ['to', 'morse'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
|
74
src/pages/tools-by-category/index.tsx
Normal file
74
src/pages/tools-by-category/index.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
CardContent,
|
||||
Divider,
|
||||
Stack,
|
||||
useTheme
|
||||
} from '@mui/material';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import { getToolsByCategory, tools } from '../../tools';
|
||||
import Button from '@mui/material/Button';
|
||||
import Hero from 'components/Hero';
|
||||
import AllTools from '../../components/allTools/AllTools';
|
||||
import { capitalizeFirstLetter } from '../../utils/string';
|
||||
import toolsPng from '@assets/tools.png';
|
||||
|
||||
export default function Home() {
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const { categoryName } = useParams();
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
padding={5}
|
||||
display={'flex'}
|
||||
flexDirection={'column'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
width={'100%'}
|
||||
>
|
||||
<Hero />
|
||||
</Box>
|
||||
<Divider sx={{ borderColor: theme.palette.primary.main }} />
|
||||
<Box width={'100%'} mt={3} ml={7} padding={3}>
|
||||
<Typography
|
||||
fontSize={22}
|
||||
color={theme.palette.primary.main}
|
||||
>{`All ${capitalizeFirstLetter(categoryName)} Tools`}</Typography>
|
||||
<Grid container spacing={2} mt={2}>
|
||||
{getToolsByCategory()
|
||||
.find(({ type }) => type === categoryName)
|
||||
?.tools?.map((tool) => (
|
||||
<Grid item xs={12} md={4} key={tool.path}>
|
||||
<Stack
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.background.default // Change this to your desired hover color
|
||||
}
|
||||
}}
|
||||
onClick={() => navigate('/' + tool.path)}
|
||||
direction={'row'}
|
||||
spacing={2}
|
||||
padding={2}
|
||||
border={1}
|
||||
borderRadius={2}
|
||||
>
|
||||
<img width={100} src={tool.image ?? toolsPng} />
|
||||
<Box>
|
||||
<Link to={'/' + tool.path}>{tool.name}</Link>
|
||||
<Typography sx={{ mt: 2 }}>
|
||||
{tool.shortDescription}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user