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,20 +41,39 @@ 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'} justifyContent={'space-between'} spacing={2}>
<Stack direction={'row'} alignItems={'center'} spacing={1}> <Stack direction={'row'} alignItems={'center'} spacing={1}>
<IconButton onClick={() => navigate('/')}> <IconButton onClick={() => navigate('/')}>
<ArrowBackIcon color={'primary'} /> <ArrowBackIcon color={'primary'} />
</IconButton> </IconButton>
<Typography fontSize={22} color={theme.palette.primary.main}>{`All ${ <Typography
fontSize={22}
color={theme.palette.primary.main}
>{`All ${
getToolsByCategory().find( getToolsByCategory().find(
(category) => category.type === categoryName (category) => category.type === categoryName
)!.rawTitle )!.rawTitle
} Tools`}</Typography> } Tools`}</Typography>
</Stack> </Stack>
<TextField
placeholder={'Search'}
InputProps={{
endAdornment: <SearchIcon />,
sx: {
borderRadius: 4,
backgroundColor: 'background.paper',
maxWidth: 400
}
}}
onChange={(event) => setSearchTerm(event.target.value)}
/>
</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 ?? [],
searchTerm
).map((tool, index) => (
<Grid item xs={12} md={6} lg={4} key={tool.path}> <Grid item xs={12} md={6} lg={4} key={tool.path}>
<Stack <Stack
sx={{ sx={{