feat: search tools

This commit is contained in:
Ibrahima G. Coulibaly
2024-06-22 23:31:00 +01:00
parent 23f50ffead
commit 455a06c525
6 changed files with 117 additions and 79 deletions

View File

@@ -26,7 +26,12 @@
"ecmaVersion": 11, "ecmaVersion": 11,
"sourceType": "module" "sourceType": "module"
}, },
"plugins": ["react", "react-hooks", "@typescript-eslint", "tailwindcss"], "plugins": [
"react",
"react-hooks",
"@typescript-eslint",
"tailwindcss"
],
"rules": { "rules": {
"react-hooks/rules-of-hooks": "error", "react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn", "react-hooks/exhaustive-deps": "warn",
@@ -36,6 +41,7 @@
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"tailwindcss/classnames-order": "warn", "tailwindcss/classnames-order": "warn",
"tailwindcss/no-custom-classname": "warn", "tailwindcss/no-custom-classname": "warn",
"tailwindcss/no-contradicting-classname": "error" "tailwindcss/no-contradicting-classname": "error",
"@typescript-eslint/ban-types": "off"
} }
} }

104
.idea/workspace.xml generated
View File

@@ -4,43 +4,13 @@
<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: react helmet"> <list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: tools normalized">
<change afterPath="$PROJECT_DIR$/src/pages/images/imageTools.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/meta.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/images/png/pngTools.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/string/split/meta.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/string/stringTools.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/tools/defineTool.tsx" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/tools/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.eslintrc" beforeDir="false" afterPath="$PROJECT_DIR$/.eslintrc" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.eslintrc" beforeDir="false" afterPath="$PROJECT_DIR$/.eslintrc" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.github/workflows/ci.yml" beforeDir="false" afterPath="$PROJECT_DIR$/.github/workflows/ci.yml" 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$/.vitest/setup.ts" beforeDir="false" afterPath="$PROJECT_DIR$/.vitest/setup.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pnpm-lock.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pnpm-lock.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/postcss.config.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/postcss.config.mjs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/App.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/App.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/Loading.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Loading.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/Navbar/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Navbar/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/ToolHeader.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolHeader.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/config/routesConfig.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/config/routesConfig.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/useDebounce.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/useDebounce.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/usePrevious.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/usePrevious.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/useTimeout.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/useTimeout.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/hooks/useUpdateEffect.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/hooks/useUpdateEffect.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/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/home/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/home/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/ImagesConfig.tsx" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/meta.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/meta.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/index.tsx" 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/pages/images/png/PngConfig.tsx" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/tools/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/tools/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/png/change-colors-in-png/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/images/png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/images/png/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/string/StringConfig.tsx" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/string/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/string/split/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/string/split/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tailwind.config.mjs" beforeDir="false" afterPath="$PROJECT_DIR$/tailwind.config.mjs" 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" />
@@ -69,32 +39,32 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent">{
"keyToString": { &quot;keyToString&quot;: {
"ASKED_ADD_EXTERNAL_FILES": "true", &quot;ASKED_ADD_EXTERNAL_FILES&quot;: &quot;true&quot;,
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true", &quot;ASKED_SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
"RunOnceActivity.OpenProjectViewOnStart": "true", &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
"RunOnceActivity.ShowReadmeOnStart": "true", &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
"git-widget-placeholder": "main", &quot;git-widget-placeholder&quot;: &quot;main&quot;,
"ignore.virus.scanning.warn.message": "true", &quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
"kotlin-language-version-configured": "true", &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
"last_opened_file_path": "C:/Users/HP/IdeaProjects/omni-tools/src/pages/string/split", &quot;last_opened_file_path&quot;: &quot;C:/Users/HP/IdeaProjects/omni-tools/src/pages/string/split&quot;,
"node.js.detected.package.eslint": "true", &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
"node.js.detected.package.tslint": "true", &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
"node.js.selected.package.eslint": "(autodetect)", &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
"node.js.selected.package.tslint": "(autodetect)", &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
"nodejs_package_manager_path": "npm", &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
"npm.dev.executor": "Run", &quot;npm.dev.executor&quot;: &quot;Run&quot;,
"npm.prebuild.executor": "Run", &quot;npm.prebuild.executor&quot;: &quot;Run&quot;,
"prettierjs.PrettierConfiguration.Package": "C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\prettier", &quot;prettierjs.PrettierConfiguration.Package&quot;: &quot;C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\prettier&quot;,
"project.structure.last.edited": "Problems", &quot;project.structure.last.edited&quot;: &quot;Problems&quot;,
"project.structure.proportion": "0.0", &quot;project.structure.proportion&quot;: &quot;0.0&quot;,
"project.structure.side.proportion": "0.2", &quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
"settings.editor.selected.configurable": "settings.typescriptcompiler", &quot;settings.editor.selected.configurable&quot;: &quot;settings.typescriptcompiler&quot;,
"ts.external.directory.path": "C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib", &quot;ts.external.directory.path&quot;: &quot;C:\\Users\\HP\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib&quot;,
"vue.rearranger.settings.migration": "true" &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}]]></component> }</component>
<component name="ReactDesignerToolWindowState"> <component name="ReactDesignerToolWindowState">
<option name="myId2Visible"> <option name="myId2Visible">
<map> <map>
@@ -161,7 +131,8 @@
<workItem from="1719006887776" duration="7000" /> <workItem from="1719006887776" duration="7000" />
<workItem from="1719006951159" duration="2377000" /> <workItem from="1719006951159" duration="2377000" />
<workItem from="1719021128819" duration="3239000" /> <workItem from="1719021128819" duration="3239000" />
<workItem from="1719083989394" duration="6308000" /> <workItem from="1719083989394" duration="7971000" />
<workItem from="1719092003308" duration="3285000" />
</task> </task>
<task id="LOCAL-00001" summary="feat: use vite and ts"> <task id="LOCAL-00001" summary="feat: use vite and ts">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -339,7 +310,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1719085085537</updated> <updated>1719085085537</updated>
</task> </task>
<option name="localTasksCounter" value="23" /> <task id="LOCAL-00023" summary="feat: tools normalized">
<option name="closed" value="true" />
<created>1719090379202</created>
<option name="number" value="00023" />
<option name="presentableId" value="LOCAL-00023" />
<option name="project" value="LOCAL" />
<updated>1719090379202</updated>
</task>
<option name="localTasksCounter" value="24" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -379,7 +358,8 @@
<MESSAGE value="chore: remove prebuild" /> <MESSAGE value="chore: remove prebuild" />
<MESSAGE value="chore: idea config" /> <MESSAGE value="chore: idea config" />
<MESSAGE value="feat: react helmet" /> <MESSAGE value="feat: react helmet" />
<option name="LAST_COMMIT_MESSAGE" value="feat: react helmet" /> <MESSAGE value="feat: tools normalized" />
<option name="LAST_COMMIT_MESSAGE" value="feat: tools normalized" />
</component> </component>
<component name="XSLT-Support.FileAssociations.UIState"> <component name="XSLT-Support.FileAssociations.UIState">
<expand /> <expand />

View File

@@ -1,8 +1,11 @@
import { Box, Stack, TextField } from '@mui/material'; import { Autocomplete, Box, 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 SearchIcon from '@mui/icons-material/Search';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { filterTools, tools } from '../../tools';
import { useState } from 'react';
import { DefinedTool } from '../../tools/defineTool';
const exampleTools: { label: string; url: string }[] = [ const exampleTools: { label: string; url: string }[] = [
{ {
@@ -20,7 +23,15 @@ const exampleTools: { label: string; url: string }[] = [
]; ];
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}
@@ -32,7 +43,6 @@ export default function Home() {
> >
<Box width={'60%'}> <Box width={'60%'}>
<Stack mb={1} direction={'row'} spacing={1}> <Stack mb={1} direction={'row'} spacing={1}>
{' '}
<Typography fontSize={30}>Transform Your Workflow with </Typography> <Typography fontSize={30}>Transform Your Workflow with </Typography>
<Typography fontSize={30} color={'primary'}> <Typography fontSize={30} color={'primary'}>
Omni Tools Omni Tools
@@ -45,13 +55,36 @@ export default function Home() {
your browser. your browser.
</Typography> </Typography>
<Autocomplete
sx={{ mb: 2 }}
autoHighlight
options={filteredTools}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<TextField <TextField
{...params}
fullWidth fullWidth
placeholder={'Search all tools'} placeholder={'Search all tools'}
sx={{ borderRadius: 2 }} sx={{ borderRadius: 2 }}
InputProps={{ InputProps={{
...params.InputProps,
endAdornment: <SearchIcon /> 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={1} mt={2}> <Grid container spacing={1} mt={2}>
{exampleTools.map((tool) => ( {exampleTools.map((tool) => (

View File

@@ -3,9 +3,9 @@ import { lazy } from 'react';
export const tool = defineTool('png', { export const tool = defineTool('png', {
path: 'change-colors', path: 'change-colors',
name: 'Change colors in PNG', name: 'PNG color replacer',
description: 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.", "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",
keywords: ['png', 'split'], keywords: ['png', 'color'],
component: lazy(() => import('./index')) component: lazy(() => import('./index'))
}); });

View File

@@ -9,7 +9,7 @@ interface ToolOptions {
description: string; description: string;
} }
interface DefinedTool { export interface DefinedTool {
path: string; path: string;
name: string; name: string;
description: string; description: string;

View File

@@ -1,4 +1,23 @@
import { stringTools } from '../pages/string/stringTools'; import { stringTools } from '../pages/string/stringTools';
import { imageTools } from '../pages/images/imageTools'; import { imageTools } from '../pages/images/imageTools';
import { DefinedTool } from './defineTool';
export const tools = [...stringTools, ...imageTools]; export const tools: DefinedTool[] = [...stringTools, ...imageTools];
export const filterTools = (
tools: DefinedTool[],
query: string
): DefinedTool[] => {
if (!query) return tools;
const lowerCaseQuery = query.toLowerCase();
return tools.filter(
(tool) =>
tool.name.toLowerCase().includes(lowerCaseQuery) ||
tool.description.toLowerCase().includes(lowerCaseQuery) ||
tool.keywords.some((keyword) =>
keyword.toLowerCase().includes(lowerCaseQuery)
)
);
};