diff --git a/src/app/App.tsx b/src/app/App.tsx index acc92d3..4e970a4 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -10,11 +10,13 @@ import { useTheme } from '@/shared/lib/hook/useTheme/useTheme'; import { useAppDispatch } from '@/shared/lib/hook/useAppDispatch/useAppDispatch'; import { MainLayout } from '@/shared/layouts/MainLayout'; import { AppLoaderLayout } from '@/shared/layouts/AppLoaderLayout'; +import { useAppToolbar } from './lib/useAppToolbar'; function App() { const { theme } = useTheme(); const dispatch = useAppDispatch(); const inited = useSelector(getUserInited); + const toolbar = useAppToolbar(); useEffect(() => { dispatch(initAuthData()); @@ -35,6 +37,7 @@ function App() { header={} content={} sidebar={} + toolbar={toolbar} /> diff --git a/src/app/lib/useAppToolbar.tsx b/src/app/lib/useAppToolbar.tsx new file mode 100644 index 0000000..657cd6d --- /dev/null +++ b/src/app/lib/useAppToolbar.tsx @@ -0,0 +1,15 @@ +import { ReactElement } from 'react'; +import { AppRoutes } from '@/shared/const/router'; +import { ScrollToolbar } from '@/widgets/ScrollToolbar'; +import { useRouteChange } from '@/shared/lib/router/useRouteChange'; + +export function useAppToolbar() { + const appRoute = useRouteChange(); + + const toolbarByAppRoute: OptionalRecord = { + [AppRoutes.ARTICLES]: , + [AppRoutes.ARTICLE_DETAILS]: , + }; + + return toolbarByAppRoute[appRoute]; +} diff --git a/src/features/scrollToTopButton/index.ts b/src/features/scrollToTopButton/index.ts new file mode 100644 index 0000000..a4d47ad --- /dev/null +++ b/src/features/scrollToTopButton/index.ts @@ -0,0 +1 @@ +export { ScrollToTopButton } from './ui/ScrollToTopButton/ScrollToTopButton'; diff --git a/src/features/scrollToTopButton/ui/ScrollToTopButton/ScrollToTopButton.tsx b/src/features/scrollToTopButton/ui/ScrollToTopButton/ScrollToTopButton.tsx new file mode 100644 index 0000000..2bd4414 --- /dev/null +++ b/src/features/scrollToTopButton/ui/ScrollToTopButton/ScrollToTopButton.tsx @@ -0,0 +1,27 @@ +import { memo } from 'react'; +import { classNames } from '@/shared/lib/classNames/classNames'; +import { Icon } from '@/shared/ui/redesigned/Icon'; +import CircleIcon from '@/shared/assets/icons/circle-up.svg'; + +interface ScrollToTopButtonProps { + className?: string; +} + +export const ScrollToTopButton = memo((props: ScrollToTopButtonProps) => { + const { className } = props; + + const onCLick = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + return ( + + ); +}); diff --git a/src/shared/assets/icons/circle-up.svg b/src/shared/assets/icons/circle-up.svg new file mode 100644 index 0000000..971a4e2 --- /dev/null +++ b/src/shared/assets/icons/circle-up.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/shared/const/router.ts b/src/shared/const/router.ts index 33bf055..dae5df6 100644 --- a/src/shared/const/router.ts +++ b/src/shared/const/router.ts @@ -23,3 +23,16 @@ export const getRouteArticleEdit = (id: string) => `/articles/${id}/edit`; export const getRouteAdminPanel = () => '/admin'; export const getRouteForbidden = () => '/forbidden'; export const getRouteNotFound = () => '*'; + +export const AppRouteByPathPattern: Record = { + [getRouteMain()]: AppRoutes.MAIN, + [getRouteSettings()]: AppRoutes.SETTINGS, + [getRouteAbout()]: AppRoutes.ABOUT, + [getRouteProfile(':id')]: AppRoutes.PROFILE, + [getRouteArticles()]: AppRoutes.ARTICLES, + [getRouteArticleDetails(':id')]: AppRoutes.ARTICLE_DETAILS, + [getRouteArticleCreate()]: AppRoutes.ARTICLE_CREATE, + [getRouteArticleEdit(':id')]: AppRoutes.ARTICLE_EDIT, + [getRouteAdminPanel()]: AppRoutes.ADMIN_PANEL, + [getRouteForbidden()]: AppRoutes.FORBIDDEN, +}; diff --git a/src/shared/layouts/MainLayout/MainLayout.module.scss b/src/shared/layouts/MainLayout/MainLayout.module.scss index edd1bcc..788cb49 100644 --- a/src/shared/layouts/MainLayout/MainLayout.module.scss +++ b/src/shared/layouts/MainLayout/MainLayout.module.scss @@ -35,4 +35,5 @@ .toolbar { height: 100%; + width: 100%; } diff --git a/src/shared/lib/router/useRouteChange.tsx b/src/shared/lib/router/useRouteChange.tsx new file mode 100644 index 0000000..712c126 --- /dev/null +++ b/src/shared/lib/router/useRouteChange.tsx @@ -0,0 +1,18 @@ +import { matchPath, useLocation } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { AppRouteByPathPattern, AppRoutes } from '@/shared/const/router'; + +export function useRouteChange() { + const location = useLocation(); + const [appRoute, setAppRoute] = useState(AppRoutes.MAIN); + + useEffect(() => { + Object.entries(AppRouteByPathPattern).forEach(([pattern, route]) => { + if (matchPath(pattern, location.pathname)) { + setAppRoute(route); + } + }); + }, [location.pathname]); + + return appRoute; +} diff --git a/src/widgets/ScrollToolbar/index.ts b/src/widgets/ScrollToolbar/index.ts new file mode 100644 index 0000000..05e7826 --- /dev/null +++ b/src/widgets/ScrollToolbar/index.ts @@ -0,0 +1 @@ +export { ScrollToolbar } from './ui/ScrollToolbar/ScrollToolbar'; diff --git a/src/widgets/ScrollToolbar/ui/ScrollToolbar/ScrollToolbar.module.scss b/src/widgets/ScrollToolbar/ui/ScrollToolbar/ScrollToolbar.module.scss new file mode 100644 index 0000000..74ab4b9 --- /dev/null +++ b/src/widgets/ScrollToolbar/ui/ScrollToolbar/ScrollToolbar.module.scss @@ -0,0 +1,3 @@ +.ScrollToolbar { + height: 100%; +} diff --git a/src/widgets/ScrollToolbar/ui/ScrollToolbar/ScrollToolbar.tsx b/src/widgets/ScrollToolbar/ui/ScrollToolbar/ScrollToolbar.tsx new file mode 100644 index 0000000..0956db9 --- /dev/null +++ b/src/widgets/ScrollToolbar/ui/ScrollToolbar/ScrollToolbar.tsx @@ -0,0 +1,24 @@ +import { memo } from 'react'; +import { classNames } from '@/shared/lib/classNames/classNames'; +import cls from './ScrollToolbar.module.scss'; +import { VStack } from '@/shared/ui/redesigned/Stack'; +import { ScrollToTopButton } from '@/features/scrollToTopButton'; + +interface ScrollToolbarProps { + className?: string; +} + +export const ScrollToolbar = memo((props: ScrollToolbarProps) => { + const { className } = props; + + return ( + + + + ); +});