feat: tool search by category

This commit is contained in:
Ibrahima G. Coulibaly
2025-04-05 00:28:31 +00:00
parent a039bbe0f0
commit 8047d32734
3 changed files with 114 additions and 97 deletions

74
.idea/workspace.xml generated
View File

@@ -4,16 +4,10 @@
<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: protect pdf"> <list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="chore: readme img and fix broken link">
<change afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/image-to-text/index.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/image-to-text/meta.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/image-to-text/service.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/image-to-text/types.ts" 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$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/components/Hero.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Hero.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools-by-category/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/result/ToolTextResult.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/result/ToolTextResult.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/generic/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/generic/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" />
@@ -415,31 +409,9 @@
<workItem from="1743458576265" duration="13083000" /> <workItem from="1743458576265" duration="13083000" />
<workItem from="1743690613245" duration="77000" /> <workItem from="1743690613245" duration="77000" />
<workItem from="1743691250813" duration="1550000" /> <workItem from="1743691250813" duration="1550000" />
<workItem from="1743699386059" duration="8791000" /> <workItem from="1743699386059" duration="11195000" />
</task> <workItem from="1743782726563" duration="2444000" />
<task id="LOCAL-00141" summary="feat: ToolContent.tsx"> <workItem from="1743811558991" duration="1279000" />
<option name="closed" value="true" />
<created>1741211604972</created>
<option name="number" value="00141" />
<option name="presentableId" value="LOCAL-00141" />
<option name="project" value="LOCAL" />
<updated>1741211604972</updated>
</task>
<task id="LOCAL-00142" summary="chore: smooth scroll for use this tool and examles">
<option name="closed" value="true" />
<created>1741414797155</created>
<option name="number" value="00142" />
<option name="presentableId" value="LOCAL-00142" />
<option name="project" value="LOCAL" />
<updated>1741414797155</updated>
</task>
<task id="LOCAL-00143" summary="feat: minify json">
<option name="closed" value="true" />
<created>1741416193639</created>
<option name="number" value="00143" />
<option name="presentableId" value="LOCAL-00143" />
<option name="project" value="LOCAL" />
<updated>1741416193639</updated>
</task> </task>
<task id="LOCAL-00144" summary="feat: stringify json"> <task id="LOCAL-00144" summary="feat: stringify json">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -809,7 +781,31 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1743705749057</updated> <updated>1743705749057</updated>
</task> </task>
<option name="localTasksCounter" value="190" /> <task id="LOCAL-00190" summary="feat: image to text">
<option name="closed" value="true" />
<created>1743710133267</created>
<option name="number" value="00190" />
<option name="presentableId" value="LOCAL-00190" />
<option name="project" value="LOCAL" />
<updated>1743710133267</updated>
</task>
<task id="LOCAL-00191" summary="chore: hideCopy if video or audio">
<option name="closed" value="true" />
<created>1743710669869</created>
<option name="number" value="00191" />
<option name="presentableId" value="LOCAL-00191" />
<option name="project" value="LOCAL" />
<updated>1743710669869</updated>
</task>
<task id="LOCAL-00192" summary="chore: readme img and fix broken link">
<option name="closed" value="true" />
<created>1743811980098</created>
<option name="number" value="00192" />
<option name="presentableId" value="LOCAL-00192" />
<option name="project" value="LOCAL" />
<updated>1743811980098</updated>
</task>
<option name="localTasksCounter" value="193" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -856,9 +852,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: background removal" />
<MESSAGE value="feat: split pdf" />
<MESSAGE value="fix: typo" />
<MESSAGE value="chore: result file name" /> <MESSAGE value="chore: result file name" />
<MESSAGE value="chore: text result extensions" /> <MESSAGE value="chore: text result extensions" />
<MESSAGE value="chore: show new tools in landing" /> <MESSAGE value="chore: show new tools in landing" />
@@ -881,7 +874,10 @@
<MESSAGE value="fix: tests" /> <MESSAGE value="fix: tests" />
<MESSAGE value="chore: uninstall @jspawn/ghostscript-wasm" /> <MESSAGE value="chore: uninstall @jspawn/ghostscript-wasm" />
<MESSAGE value="feat: protect pdf" /> <MESSAGE value="feat: protect pdf" />
<option name="LAST_COMMIT_MESSAGE" value="feat: protect pdf" /> <MESSAGE value="feat: image to text" />
<MESSAGE value="chore: hideCopy if video or audio" />
<MESSAGE value="chore: readme img and fix broken link" />
<option name="LAST_COMMIT_MESSAGE" value="chore: readme img and fix broken link" />
</component> </component>
<component name="XSLT-Support.FileAssociations.UIState"> <component name="XSLT-Support.FileAssociations.UIState">
<expand /> <expand />

View File

@@ -35,7 +35,7 @@ export default function Hero() {
newInputValue: string newInputValue: string
) => { ) => {
setInputValue(newInputValue); setInputValue(newInputValue);
setFilteredTools(_.shuffle(filterTools(tools, newInputValue))); setFilteredTools(filterTools(tools, newInputValue));
}; };
return ( return (

View File

@@ -1,8 +1,8 @@
import { Box, Divider, Stack, useTheme } from '@mui/material'; import { Box, Divider, Stack, TextField, useTheme } 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 { Link, useNavigate, useParams } from 'react-router-dom'; import { Link, useNavigate, useParams } from 'react-router-dom';
import { getToolsByCategory } from '../../tools'; import { filterTools, getToolsByCategory } from '../../tools';
import Hero from 'components/Hero'; import Hero from 'components/Hero';
import { capitalizeFirstLetter } from '@utils/string'; import { capitalizeFirstLetter } from '@utils/string';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
@@ -12,12 +12,14 @@ import IconButton from '@mui/material/IconButton';
import { ArrowBack } from '@mui/icons-material'; import { ArrowBack } from '@mui/icons-material';
import BackButton from '@components/BackButton'; import BackButton from '@components/BackButton';
import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import SearchIcon from '@mui/icons-material/Search';
export default function Home() { export default function ToolsByCategory() {
const navigate = useNavigate(); const navigate = useNavigate();
const theme = useTheme(); const theme = useTheme();
const mainContentRef = React.useRef<HTMLDivElement>(null); const mainContentRef = React.useRef<HTMLDivElement>(null);
const { categoryName } = useParams(); const { categoryName } = useParams();
const [searchTerm, setSearchTerm] = React.useState<string>('');
useEffect(() => { useEffect(() => {
if (mainContentRef.current) { if (mainContentRef.current) {
@@ -39,62 +41,81 @@ export default function Home() {
</Box> </Box>
<Divider sx={{ borderColor: theme.palette.primary.main }} /> <Divider sx={{ borderColor: theme.palette.primary.main }} />
<Box ref={mainContentRef} mt={3} ml={{ xs: 1, md: 2, lg: 3 }} padding={3}> <Box ref={mainContentRef} mt={3} ml={{ xs: 1, md: 2, lg: 3 }} padding={3}>
<Stack direction={'row'} alignItems={'center'} spacing={1}> <Stack direction={'row'} justifyContent={'space-between'} spacing={2}>
<IconButton onClick={() => navigate('/')}> <Stack direction={'row'} alignItems={'center'} spacing={1}>
<ArrowBackIcon color={'primary'} /> <IconButton onClick={() => navigate('/')}>
</IconButton> <ArrowBackIcon color={'primary'} />
<Typography fontSize={22} color={theme.palette.primary.main}>{`All ${ </IconButton>
getToolsByCategory().find( <Typography
(category) => category.type === categoryName fontSize={22}
)!.rawTitle color={theme.palette.primary.main}
} Tools`}</Typography> >{`All ${
getToolsByCategory().find(
(category) => category.type === categoryName
)!.rawTitle
} Tools`}</Typography>
</Stack>
<TextField
placeholder={'Search'}
InputProps={{
endAdornment: <SearchIcon />,
sx: {
borderRadius: 4,
backgroundColor: 'background.paper',
maxWidth: 400
}
}}
onChange={(event) => setSearchTerm(event.target.value)}
/>
</Stack> </Stack>
<Grid container spacing={2} mt={2}> <Grid container spacing={2} mt={2}>
{getToolsByCategory() {filterTools(
.find(({ type }) => type === categoryName) getToolsByCategory().find(({ type }) => type === categoryName)
?.tools?.map((tool, index) => ( ?.tools ?? [],
<Grid item xs={12} md={6} lg={4} key={tool.path}> searchTerm
<Stack ).map((tool, index) => (
sx={{ <Grid item xs={12} md={6} lg={4} key={tool.path}>
backgroundColor: 'background.paper', <Stack
boxShadow: `5px 4px 2px ${ sx={{
theme.palette.mode === 'dark' ? 'black' : '#E9E9ED' backgroundColor: 'background.paper',
}`, boxShadow: `5px 4px 2px ${
cursor: 'pointer', theme.palette.mode === 'dark' ? 'black' : '#E9E9ED'
height: '100%', }`,
'&:hover': { cursor: 'pointer',
backgroundColor: theme.palette.background.hover height: '100%',
} '&:hover': {
}} backgroundColor: theme.palette.background.hover
onClick={() => navigate('/' + tool.path)} }
direction={'row'} }}
alignItems={'center'} onClick={() => navigate('/' + tool.path)}
spacing={2} direction={'row'}
padding={2} alignItems={'center'}
border={`1px solid ${theme.palette.background.default}`} spacing={2}
borderRadius={2} padding={2}
> border={`1px solid ${theme.palette.background.default}`}
<Icon borderRadius={2}
icon={tool.icon ?? 'ph:compass-tool-thin'} >
fontSize={'60px'} <Icon
color={categoriesColors[index % categoriesColors.length]} icon={tool.icon ?? 'ph:compass-tool-thin'}
/> fontSize={'60px'}
<Box> color={categoriesColors[index % categoriesColors.length]}
<Link />
style={{ <Box>
fontSize: 20 <Link
}} style={{
to={'/' + tool.path} fontSize: 20
> }}
{tool.name} to={'/' + tool.path}
</Link> >
<Typography sx={{ mt: 2 }}> {tool.name}
{tool.shortDescription} </Link>
</Typography> <Typography sx={{ mt: 2 }}>
</Box> {tool.shortDescription}
</Stack> </Typography>
</Grid> </Box>
))} </Stack>
</Grid>
))}
</Grid> </Grid>
</Box> </Box>
</Box> </Box>