mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-16 12:39:31 +02:00
feat: tools by category
This commit is contained in:
44
.idea/workspace.xml
generated
44
.idea/workspace.xml
generated
@@ -4,25 +4,15 @@
|
|||||||
<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="feat: create transparent png">
|
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: shortDescription">
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/assets/tools.png" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/components/Hero.tsx" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" afterDir="false" />
|
||||||
<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$/scripts/create-tool.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/create-tool.mjs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/components/ToolInputAndResult.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolInputAndResult.tsx" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/components/ToolLayout.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolLayout.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/components/ToolLayout.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolLayout.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/components/allTools/ToolCard.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/allTools/ToolCard.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/config/routesConfig.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/config/routesConfig.tsx" 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/Examples.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/examples/Examples.tsx" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/components/input/ToolTextInput.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/input/ToolTextInput.tsx" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/home/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/home/index.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/pages/home/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/home/index.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/image/png/change-colors-in-png/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/image/png/change-colors-in-png/meta.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/utils/string.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/string.ts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/image/png/create-transparent/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/image/png/create-transparent/meta.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/number/sum/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/number/sum/meta.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/string/join/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/join/index.tsx" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/string/join/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/join/meta.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/string/split/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/split/meta.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/pages/string/to-morse/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/to-morse/meta.ts" 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" />
|
|
||||||
</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" />
|
||||||
@@ -202,14 +192,6 @@
|
|||||||
<workItem from="1719273044735" duration="9847000" />
|
<workItem from="1719273044735" duration="9847000" />
|
||||||
<workItem from="1719294110005" duration="3842000" />
|
<workItem from="1719294110005" duration="3842000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00009" summary="chore: split string tools ui">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1718996769014</created>
|
|
||||||
<option name="number" value="00009" />
|
|
||||||
<option name="presentableId" value="LOCAL-00009" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1718996769014</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00010" summary="chore: use formik">
|
<task id="LOCAL-00010" summary="chore: use formik">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
<created>1718997842506</created>
|
<created>1718997842506</created>
|
||||||
@@ -594,7 +576,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1719297880629</updated>
|
<updated>1719297880629</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="58" />
|
<task id="LOCAL-00058" summary="feat: shortDescription">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1719301172510</created>
|
||||||
|
<option name="number" value="00058" />
|
||||||
|
<option name="presentableId" value="LOCAL-00058" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1719301172510</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="59" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -615,7 +605,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="feat: copy and import file" />
|
|
||||||
<MESSAGE value="refactor: tool options components" />
|
<MESSAGE value="refactor: tool options components" />
|
||||||
<MESSAGE value="fix: join text service" />
|
<MESSAGE value="fix: join text service" />
|
||||||
<MESSAGE value="test: join service" />
|
<MESSAGE value="test: join service" />
|
||||||
@@ -640,7 +629,8 @@
|
|||||||
<MESSAGE value="fix: readme" />
|
<MESSAGE value="fix: readme" />
|
||||||
<MESSAGE value="refactor: tool input and result" />
|
<MESSAGE value="refactor: tool input and result" />
|
||||||
<MESSAGE value="feat: create transparent png" />
|
<MESSAGE value="feat: create transparent png" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="feat: create transparent png" />
|
<MESSAGE value="feat: shortDescription" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="feat: shortDescription" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XSLT-Support.FileAssociations.UIState">
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
<expand />
|
<expand />
|
||||||
|
BIN
src/assets/tools.png
Normal file
BIN
src/assets/tools.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
100
src/components/Hero.tsx
Normal file
100
src/components/Hero.tsx
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import { Autocomplete, Box, Stack, TextField } from '@mui/material';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
import Grid from '@mui/material/Grid';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { DefinedTool } from '@tools/defineTool';
|
||||||
|
import { filterTools, tools } from '@tools/index';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
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 Hero() {
|
||||||
|
const [inputValue, setInputValue] = useState<string>('');
|
||||||
|
const [filteredTools, setFilteredTools] = useState<DefinedTool[]>(tools);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const handleInputChange = (
|
||||||
|
event: React.ChangeEvent<{}>,
|
||||||
|
newInputValue: string
|
||||||
|
) => {
|
||||||
|
setInputValue(newInputValue);
|
||||||
|
setFilteredTools(filterTools(tools, newInputValue));
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<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.shortDescription}</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>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
@@ -5,6 +5,7 @@ import ToolHeader from './ToolHeader';
|
|||||||
import Separator from '@tools/Separator';
|
import Separator from '@tools/Separator';
|
||||||
import AllTools from './allTools/AllTools';
|
import AllTools from './allTools/AllTools';
|
||||||
import { getToolsByCategory } from '@tools/index';
|
import { getToolsByCategory } from '@tools/index';
|
||||||
|
import { capitalizeFirstLetter } from '../utils/string';
|
||||||
|
|
||||||
export default function ToolLayout({
|
export default function ToolLayout({
|
||||||
children,
|
children,
|
||||||
@@ -43,7 +44,10 @@ export default function ToolLayout({
|
|||||||
<ToolHeader title={title} description={description} image={image} />
|
<ToolHeader title={title} description={description} image={image} />
|
||||||
{children}
|
{children}
|
||||||
<Separator backgroundColor="#5581b5" margin="50px" />
|
<Separator backgroundColor="#5581b5" margin="50px" />
|
||||||
<AllTools title="All Text Tools" toolCards={otherCategoryTools} />
|
<AllTools
|
||||||
|
title={`All ${capitalizeFirstLetter(type)} tools`}
|
||||||
|
toolCards={otherCategoryTools}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@@ -3,12 +3,17 @@ import { Navigate } from 'react-router-dom';
|
|||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
|
|
||||||
const Home = lazy(() => import('../pages/home'));
|
const Home = lazy(() => import('../pages/home'));
|
||||||
|
const ToolsByCategory = lazy(() => import('../pages/tools-by-category'));
|
||||||
|
|
||||||
const routes: RouteObject[] = [
|
const routes: RouteObject[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
element: <Home />
|
element: <Home />
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/categories/:categoryName',
|
||||||
|
element: <ToolsByCategory />
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
element: <Navigate to="404" />
|
element: <Navigate to="404" />
|
||||||
|
@@ -1,45 +1,14 @@
|
|||||||
import {
|
import { Box, Card, CardContent, Stack } from '@mui/material';
|
||||||
Autocomplete,
|
|
||||||
Box,
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
Stack,
|
|
||||||
TextField
|
|
||||||
} from '@mui/material';
|
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import SearchIcon from '@mui/icons-material/Search';
|
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { filterTools, getToolsByCategory, tools } from '../../tools';
|
import { getToolsByCategory } from '../../tools';
|
||||||
import { useState } from 'react';
|
|
||||||
import { DefinedTool } from '@tools/defineTool';
|
|
||||||
import Button from '@mui/material/Button';
|
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() {
|
export default function Home() {
|
||||||
const navigate = useNavigate();
|
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 (
|
return (
|
||||||
<Box
|
<Box
|
||||||
padding={5}
|
padding={5}
|
||||||
@@ -49,78 +18,8 @@ export default function Home() {
|
|||||||
justifyContent={'center'}
|
justifyContent={'center'}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
>
|
>
|
||||||
<Box width={'60%'}>
|
<Hero />
|
||||||
<Stack mb={1} direction={'row'} spacing={1}>
|
<Grid width={'80%'} container mt={2} spacing={2}>
|
||||||
<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.shortDescription}</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) => (
|
{getToolsByCategory().map((category) => (
|
||||||
<Grid key={category.type} item xs={6}>
|
<Grid key={category.type} item xs={6}>
|
||||||
<Card>
|
<Card>
|
||||||
@@ -138,6 +37,7 @@ export default function Home() {
|
|||||||
justifyContent={'space-between'}
|
justifyContent={'space-between'}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
onClick={() => navigate('/categories/' + category.type)}
|
||||||
variant={'contained'}
|
variant={'contained'}
|
||||||
>{`See all ${category.title}`}</Button>
|
>{`See all ${category.title}`}</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -151,6 +51,5 @@ export default function Home() {
|
|||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
export function capitalizeFirstLetter(string: string) {
|
export function capitalizeFirstLetter(string: string | undefined) {
|
||||||
|
if (!string) return '';
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user