Merge remote-tracking branch 'origin/string-join'

# Conflicts:
#	.idea/workspace.xml
#	src/tools/defineTool.tsx
This commit is contained in:
Ibrahima G. Coulibaly
2024-06-25 22:12:04 +01:00
27 changed files with 730 additions and 143 deletions

View File

@@ -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>
);
}

View File

@@ -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'))
});

View File

@@ -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'],

View File

@@ -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'))
});

View 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>
);
}

View File

@@ -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>
);
}

View File

@@ -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'))
});

View File

@@ -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'))
});

View File

@@ -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'))
});

View 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>
);
}