From 19f0de8909f7228cef97f6b582479618186adb69 Mon Sep 17 00:00:00 2001 From: "Ibrahima G. Coulibaly" Date: Wed, 19 Jun 2024 21:18:35 +0100 Subject: [PATCH] feat: Split string --- package-lock.json | 10 ++++-- package.json | 2 ++ src/assets/text.png | Bin 0 -> 7717 bytes src/components/App.tsx | 16 ++++++--- src/components/Loading.tsx | 53 ++++++++++++++++++++++++++++++ src/components/ToolHeader.tsx | 18 ++++++++++ src/components/ToolLayout.tsx | 7 ++++ src/config/muiConfig.ts | 11 +++++++ src/config/routesConfig.tsx | 5 +++ src/hooks/index.ts | 4 +++ src/hooks/useDebounce.ts | 38 +++++++++++++++++++++ src/hooks/usePrevious.ts | 19 +++++++++++ src/hooks/useTimeout.ts | 30 +++++++++++++++++ src/hooks/useUpdateEffect.ts | 19 +++++++++++ src/pages/home/index.tsx | 33 +++++++++++-------- src/pages/string/StringConfig.tsx | 10 ++++++ src/pages/string/index.tsx | 5 +++ src/pages/string/split/index.tsx | 45 +++++++++++++++++++++++++ 18 files changed, 305 insertions(+), 20 deletions(-) create mode 100644 src/assets/text.png create mode 100644 src/components/Loading.tsx create mode 100644 src/components/ToolHeader.tsx create mode 100644 src/components/ToolLayout.tsx create mode 100644 src/config/muiConfig.ts create mode 100644 src/hooks/index.ts create mode 100644 src/hooks/useDebounce.ts create mode 100644 src/hooks/usePrevious.ts create mode 100644 src/hooks/useTimeout.ts create mode 100644 src/hooks/useUpdateEffect.ts create mode 100644 src/pages/string/StringConfig.tsx create mode 100644 src/pages/string/index.tsx create mode 100644 src/pages/string/split/index.tsx diff --git a/package-lock.json b/package-lock.json index 04eecab..c5761e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "@emotion/styled": "^11.11.5", "@mui/icons-material": "^5.15.20", "@mui/material": "^5.15.20", + "@types/lodash": "^4.17.5", + "lodash": "^4.17.21", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1" @@ -1976,6 +1978,11 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==" + }, "node_modules/@types/node": { "version": "20.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", @@ -5149,8 +5156,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", diff --git a/package.json b/package.json index 766c09b..d5bbb0e 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "@emotion/styled": "^11.11.5", "@mui/icons-material": "^5.15.20", "@mui/material": "^5.15.20", + "@types/lodash": "^4.17.5", + "lodash": "^4.17.21", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1" diff --git a/src/assets/text.png b/src/assets/text.png new file mode 100644 index 0000000000000000000000000000000000000000..c2044a15efed664dfed5679df343a078be87b1b4 GIT binary patch literal 7717 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 { return useRoutes(routesConfig); @@ -9,10 +13,14 @@ const AppRoutes = () => { function App() { return ( - - - - + + + + }> + + + + ) } diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx new file mode 100644 index 0000000..b4e7c97 --- /dev/null +++ b/src/components/Loading.tsx @@ -0,0 +1,53 @@ +import Typography from "@mui/material/Typography"; +import {useState} from "react"; +import clsx from "clsx"; +import Box from "@mui/material/Box"; +import {useTimeout} from "../hooks"; + +export type FuseLoadingProps = { + delay?: number; + className?: string; +}; + +/** + * FuseLoading displays a loading state with an optional delay + */ +function FuseLoading(props: FuseLoadingProps) { + const {delay = 0, className} = props; + const [showLoading, setShowLoading] = useState(!delay); + + useTimeout(() => { + setShowLoading(true); + }, delay); + + return ( +
+ + Chargement + + div": { + backgroundColor: "palette.secondary.main", + }, + }} + > +
+
+
+ +
+ ); +} + +export default FuseLoading; diff --git a/src/components/ToolHeader.tsx b/src/components/ToolHeader.tsx new file mode 100644 index 0000000..09cbf94 --- /dev/null +++ b/src/components/ToolHeader.tsx @@ -0,0 +1,18 @@ +import {Box, Stack} from "@mui/material"; +import Typography from "@mui/material/Typography"; +import textImage from '../assets/text.png' + +interface ToolHeaderProps { + title: string; + description: string; +} + +export default function ToolHeader({title, description}: ToolHeaderProps) { + return ( + + {title} + {description} + + + ) +} diff --git a/src/components/ToolLayout.tsx b/src/components/ToolLayout.tsx new file mode 100644 index 0000000..4612fcb --- /dev/null +++ b/src/components/ToolLayout.tsx @@ -0,0 +1,7 @@ +import {Box} from "@mui/material"; +import {ReactNode} from "react"; + +export default function ToolLayout({children}: { children: ReactNode }) { + return ({children}) +} diff --git a/src/config/muiConfig.ts b/src/config/muiConfig.ts new file mode 100644 index 0000000..53308fc --- /dev/null +++ b/src/config/muiConfig.ts @@ -0,0 +1,11 @@ +import {createTheme} from "@mui/material"; + +const theme = createTheme({ + typography: { + button: { + textTransform: 'none' + } + } +}); + +export default theme; diff --git a/src/config/routesConfig.tsx b/src/config/routesConfig.tsx index f68f5a1..f62024a 100644 --- a/src/config/routesConfig.tsx +++ b/src/config/routesConfig.tsx @@ -2,6 +2,7 @@ import {RouteObject} from "react-router-dom"; import {Navigate} from "react-router-dom"; import {ImagesConfig} from "../pages/images/ImagesConfig"; import {lazy} from "react"; +import {StringConfig} from "../pages/string/StringConfig"; const Home = lazy(() => import("../pages/home")); @@ -14,6 +15,10 @@ const routes: RouteObject[] = [ path: "images", children: ImagesConfig }, + { + path: "string", + children: StringConfig + }, { path: "*", element: , diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..cc9ab3f --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,4 @@ +export {default as useDebounce} from "./useDebounce"; +export {default as useTimeout} from "./useTimeout"; +export {default as usePrevious} from "./usePrevious"; +export {default as useUpdateEffect} from "./useUpdateEffect"; diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts new file mode 100644 index 0000000..4bb06ad --- /dev/null +++ b/src/hooks/useDebounce.ts @@ -0,0 +1,38 @@ +import {useCallback, useEffect, useRef} from "react"; +import _ from "lodash"; + +/** + * Debounce hook. + * @param {T} callback + * @param {number} delay + * @returns {T} + */ +function useDebounce void>( + callback: T, + delay: number, +): T { + const callbackRef = useRef(callback); + + // Update the current callback each time it changes. + useEffect(() => { + callbackRef.current = callback; + }, [callback]); + + const debouncedFn = useCallback( + _.debounce((...args: never[]) => { + callbackRef.current(...args); + }, delay), + [delay], + ); + + useEffect(() => { + // Cleanup function to cancel any pending debounced calls + return () => { + debouncedFn.cancel(); + }; + }, [debouncedFn]); + + return debouncedFn as unknown as T; +} + +export default useDebounce; diff --git a/src/hooks/usePrevious.ts b/src/hooks/usePrevious.ts new file mode 100644 index 0000000..1fec16f --- /dev/null +++ b/src/hooks/usePrevious.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef } from "react"; + +/** + * The usePrevious function is a custom hook that returns the previous value of a variable. + * It takes in a value as a parameter and returns the previous value. + */ +function usePrevious(value: T): T | undefined { + const ref = useRef(); + + // Store current value in ref + useEffect(() => { + ref.current = value; + }, [value]); + + // Return previous value (happens before update in useEffect above) + return ref.current; +} + +export default usePrevious; diff --git a/src/hooks/useTimeout.ts b/src/hooks/useTimeout.ts new file mode 100644 index 0000000..bb2ffd2 --- /dev/null +++ b/src/hooks/useTimeout.ts @@ -0,0 +1,30 @@ +import { useEffect, useRef } from "react"; + +/** + * The useTimeout function is a custom hook that sets a timeout for a given callback function. + * It takes in a callback function and a delay time in milliseconds as parameters. + * It returns nothing. + */ +function useTimeout(callback: () => void, delay: number) { + const callbackRef = useRef(callback); + + useEffect(() => { + callbackRef.current = callback; + }, [callback]); + + useEffect(() => { + let timer: NodeJS.Timeout | undefined; + + if (delay !== null && callback && typeof callback === "function") { + timer = setTimeout(callbackRef.current, delay); + } + + return () => { + if (timer) { + clearTimeout(timer); + } + }; + }, [callback, delay]); +} + +export default useTimeout; diff --git a/src/hooks/useUpdateEffect.ts b/src/hooks/useUpdateEffect.ts new file mode 100644 index 0000000..d172f8a --- /dev/null +++ b/src/hooks/useUpdateEffect.ts @@ -0,0 +1,19 @@ +import { DependencyList, EffectCallback, useEffect, useRef } from "react"; + +/** + * The useUpdateEffect function is a custom hook that behaves like useEffect, but only runs on updates and not on initial mount. + * It takes in an effect function and an optional dependency list as parameters. + * It returns nothing. + */ +const useUpdateEffect = (effect: EffectCallback, deps?: DependencyList) => { + const isInitialMount = useRef(true); + + useEffect(() => { + if (isInitialMount.current) { + isInitialMount.current = false; + } + return effect(); + }, deps); +}; + +export default useUpdateEffect; diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index b3fdbfb..07f74c4 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -1,21 +1,25 @@ -import {Box, Grid, Icon, Input, Stack, TextField} from "@mui/material"; +import {Box, Icon, Input, Stack, TextField} from "@mui/material"; +import Grid from "@mui/material/Grid"; import Typography from "@mui/material/Typography"; import SearchIcon from '@mui/icons-material/Search'; +import {useNavigate} from "react-router-dom"; +const exampleTools: { label: string; url: string }[] = [{ + label: 'Create a transparent image', + url: '' +}, + {label: 'Convert text to morse code', url: ''}, + {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: ''}, + {label: 'Pixelate an image', url: ''}, +] export default function Home() { - const exampleTools: { label: string; url: string }[] = [{ - label: 'Create a transparent image', - url: '' - }, - {label: 'Convert text to morse code', url: ''}, - {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: ''}, - {label: 'Calculate number sum', url: ''}, - {label: 'Pixelate an image', url: ''}, - ] + const navigate = useNavigate() + return ( @@ -38,6 +42,7 @@ export default function Home() { {exampleTools.map((tool) => ( navigate(tool.url)} item xs={4} key={tool.label} diff --git a/src/pages/string/StringConfig.tsx b/src/pages/string/StringConfig.tsx new file mode 100644 index 0000000..dc70628 --- /dev/null +++ b/src/pages/string/StringConfig.tsx @@ -0,0 +1,10 @@ +import {RouteObject} from "react-router-dom"; +import {lazy} from "react"; + +const StringHome = lazy(() => import("./index")); +const StringSplit = lazy(() => import("./split")); + +export const StringConfig: RouteObject[] = [ + {path: '', element: }, + {path: 'split', element: }, +] diff --git a/src/pages/string/index.tsx b/src/pages/string/index.tsx new file mode 100644 index 0000000..bf9ff71 --- /dev/null +++ b/src/pages/string/index.tsx @@ -0,0 +1,5 @@ +import {Box} from "@mui/material"; + +export default function StringHome() { + return () +} diff --git a/src/pages/string/split/index.tsx b/src/pages/string/split/index.tsx new file mode 100644 index 0000000..4b590a2 --- /dev/null +++ b/src/pages/string/split/index.tsx @@ -0,0 +1,45 @@ +import ToolHeader from "../../../components/ToolHeader"; +import ToolLayout from "../../../components/ToolLayout"; +import {Box, Stack, TextField} from "@mui/material"; +import Grid from "@mui/material/Grid"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import PublishIcon from '@mui/icons-material/Publish'; +import ContentPasteIcon from '@mui/icons-material/ContentPaste'; +import DownloadIcon from '@mui/icons-material/Download'; +import React, {useEffect, useState} from "react"; + +export default function SplitText() { + const [input, setInput] = useState(''); + const [result, setResult] = useState('') + useEffect(() => { + setResult(input.split(' ').join('\n')) + }, [input]); + return ( + + + + + + Input text + setInput(event.target.value)} fullWidth multiline rows={10}/> + + + + + + + Text pieces + + + + + + + + + + + ) +}