From f66449106d8c41d6b3d8af7e721530a10ee23f19 Mon Sep 17 00:00:00 2001 From: olyalass Date: Wed, 31 Jul 2024 12:09:35 +0200 Subject: [PATCH] feat: add responsive and refactor imports --- src/App.css | 175 +++++++++++++++- src/App.tsx | 187 +++++++++++++----- src/Pages/HomePage/HomeContent.tsx | 10 +- src/Pages/HomePage/HomeMenu.tsx | 77 +++++--- src/Pages/ListsPage/ListsContent.tsx | 21 +- src/Pages/ListsPage/ListsMenu.tsx | 111 +++++++++-- src/Pages/ListsPage/ListsPage.tsx | 10 +- src/Pages/RandomAnimePage/RandomAnimePage.tsx | 5 - src/Pages/SearchPage/SearchContent.tsx | 12 +- src/Pages/SearchPage/SearchForm.tsx | 29 ++- src/Pages/SearchPage/SearchPage.tsx | 9 +- src/api/parsers/parseAnimeResponseItem.ts | 2 +- src/api/requests/getDupesReplacement.ts | 3 +- src/components/AddToListSelect.tsx | 3 +- src/components/AnimeCard.tsx | 2 +- src/components/ContentEmpty.tsx | 2 +- src/redux/reducer.ts | 1 + .../lists/thunk/requestListAnimeData.ts | 3 +- .../thunk/requestSearchCardsData.ts | 1 + src/shared/SizeContext.ts | 3 + src/shared/index.ts | 1 + src/utils/createNavItems.tsx | 68 ++++--- src/utils/determineCardsAmountByViewport.ts | 12 +- src/utils/index.ts | 1 - src/utils/urlCreators/index.ts | 1 + 25 files changed, 558 insertions(+), 191 deletions(-) create mode 100644 src/shared/SizeContext.ts diff --git a/src/App.css b/src/App.css index 2ae7589..7d4132b 100644 --- a/src/App.css +++ b/src/App.css @@ -64,12 +64,15 @@ } .content-container { - padding: 2vh 2vw; + padding: 10px 10px; display: flex; flex-direction: column; gap: 20px; align-items: center; flex-grow: 1; + height: calc(100vh - 64px); + box-sizing: border-box; + overflow-y: scroll; } .ant-modal-body { @@ -81,11 +84,10 @@ .content-wrap { display: flex; + width: 1520px; gap: 20px; flex-wrap: wrap; justify-content: start; - width: 100%; - min-height: 80vh; } .anime-card { @@ -169,11 +171,10 @@ .anime-big-card { position: relative; display: flex; - gap: 10px; + gap: 30px; justify-content: space-between; align-items: start; padding: 3vw; - /* border: 2px solid #d29ada; */ border-radius: 10px; min-width: 60vw; max-width: 70vw; @@ -205,10 +206,6 @@ color: rgba(255, 255, 255, 0.65); } -.descriptions { - max-width: 60%; -} - .random-container { display: flex; align-items: center; @@ -249,6 +246,69 @@ position: static; } +.nav-menu i { + display: none; +} + +.ant-menu-submenu-title { + padding-inline-end: 0px !important; +} + +.search-page { + flex-direction: row; + justify-content: space-between; + align-items: start; + display: flex; +} + +.showhide-button { + display: none; +} + +.lists-sider { + min-height: calc(100vh - 64px); + padding-top: 15px; +} + +.home-sider { + height: calc(100vh - 64px); + overflow-y: scroll; +} + +.lists-page { + flex-direction: row; + justify-content: space-between; + align-items: start; + display: flex; + width: 100%; +} + +@media (max-width: 1840px) { + .content-wrap { + width: 1300px; + } +} +@media (max-width: 1580px) { + .content-wrap { + width: 1080px; + } +} +@media (max-width: 1400px) { + .content-wrap { + width: 860px; + } +} +@media (max-width: 1130px) { + .content-wrap { + width: 640px; + } +} +@media (max-width: 910px) { + .content-wrap { + width: 420px; + } +} + @media (max-width: 1400px) { .anime-big-card { align-items: center; @@ -277,4 +337,101 @@ .descriptions { max-width: unset; } + + .header-container { + width: calc(100vw - 30px); + gap: unset; + } +} + +@media (max-width: 720px) { + .lists-page { + flex-direction: column; + } + .content-container { + min-height: calc(100vh - 91px); + height: fit-content; + width: 100%; + } + .lists-sider { + min-height: calc(100vh - 91px); + flex: 0 0 150px !important; + min-width: unset !important; + } + .search-sider { + position: relative; + flex-direction: row; + flex-wrap: wrap; + max-width: unset; + min-height: unset; + width: 100vw; + height: fit-content; + border-right: none; + padding-bottom: 10px; + background-color: #f9f9f9; + } + .search-sider-closed { + height: 20px; + } + + .search-sider-closed .ant-form { + display: none; + } + + .search-sider-dark { + background-color: #001529; + color: #e4dee4a8; + } + + .ant-form { + display: flex; + flex-direction: row; + flex-wrap: wrap; + column-gap: 20px; + align-items: center; + } + + .ant-form-item:has(.ant-select) { + min-width: 100px; + } + + .search-page { + flex-direction: column; + } + + .showhide-button { + display: block; + position: absolute; + width: 90px; + bottom: -25px; + left: calc(50vw - 45px); + border-radius: 0 0 10px 10px; + color: inherit; + background-color: inherit; + appearance: none; + border: none; + padding: 5px; + cursor: pointer; + z-index: 2; + } + + .showhide-button:hover { + color: #d29ada; + } + + .content-wrap { + width: 640px; + } +} + +@media (max-width: 670px) { + .content-wrap { + width: 420px; + } +} + +@media (max-width: 442px) { + .content-wrap { + width: 220px; + } } diff --git a/src/App.tsx b/src/App.tsx index 4b248ca..f761f72 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,15 @@ import { Header } from 'antd/es/layout/layout' -import { SunOutlined, MoonOutlined } from '@ant-design/icons' -import { ConfigProvider, Layout, Input, Space, Menu, Switch } from 'antd' -import { useCallback, useEffect, useState } from 'react' +import { SunOutlined, MoonOutlined, HomeOutlined } from '@ant-design/icons' +import { + ConfigProvider, + Layout, + Input, + Space, + Menu, + Switch, + Breadcrumb, +} from 'antd' +import { useEffect, useState } from 'react' import { Routes, Route, useLocation } from 'react-router' import { Link, useNavigate } from 'react-router-dom' import { useDispatch } from 'react-redux' @@ -17,9 +25,10 @@ import { AnimeByIdPage, ListsPage, } from './pages' -import { requestLists, requestGenres, clearHomeFilters } from './redux/slices' -import { createNavItems } from './utils' +import { requestLists, requestGenres } from './redux/slices' import { SharedPage } from './pages/SharedPage' +import { burgerNavItems, navItems } from './utils/createNavItems' +import { SizeContext } from './shared/SizeContext' const isSystemThemeLight = window.matchMedia( '(prefers-color-scheme: light)', ).matches @@ -31,6 +40,32 @@ function App() { const navigate = useNavigate() const location = useLocation() + const breadItems = location.pathname + .split('/') + .slice(1) + .map((i) => ({ + key: i, + title: ( + + {i ? i[0].toUpperCase() + i.substring(1) : null} + + ), + })) + + const [isNarrowScreen, setIsNarrowScreen] = useState( + window.matchMedia('(max-width: 720px)').matches, + ) + useEffect(() => { + function handleResize() { + setIsNarrowScreen(window.matchMedia('(max-width: 720px)').matches) + } + handleResize() + window.addEventListener('resize', handleResize) + return () => { + window.removeEventListener('resize', handleResize) + } + }, []) + useEffect(() => { dispatch(requestGenres()) dispatch(requestLists()) @@ -41,59 +76,105 @@ function App() { setSearchValue('') } - const onHomePageClick = useCallback(() => { - dispatch(clearHomeFilters) - }, [dispatch]) - return ( - - - -
-
- -

Anime Universe

- -
- - setSearchValue(e.target.value)} - onSearch={onSearch} + + + + +
+
+ +

Anime Universe

+ +
+ + setSearchValue(e.target.value)} + onSearch={onSearch} + /> + + {!isNarrowScreen && ( + + )} +
+ {isNarrowScreen && ( + - - } + unCheckedChildren={} + defaultChecked={isLightTheme} + onChange={() => setIsLightTheme(!isLightTheme)} />
- } - unCheckedChildren={} - defaultChecked={isLightTheme} - onChange={() => setIsLightTheme(!isLightTheme)} - /> -
-
- - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - + + {isNarrowScreen && ( +
+ + + + ), + }, + ].concat(breadItems) + : [ + { + key: '/', + title: ( + + + + ), + }, + ] + } + /> +
+ )} + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
-
-
-
+ + + ) } diff --git a/src/Pages/HomePage/HomeContent.tsx b/src/Pages/HomePage/HomeContent.tsx index 1c89505..37dfe6b 100644 --- a/src/Pages/HomePage/HomeContent.tsx +++ b/src/Pages/HomePage/HomeContent.tsx @@ -1,4 +1,3 @@ -import { Flex } from 'antd' import { Content } from 'antd/es/layout/layout' import { useCallback, useEffect, useState } from 'react' import { useDispatch } from 'react-redux' @@ -14,6 +13,7 @@ import { AnimeCardType, DispatchType } from '../../types' import { determineCardsAmountByViewport } from '../../utils' import { requestHomeCardsData } from '../../redux/slices/homeCards/thunk' import { usePageResize, useTypedSelector } from '../../hooks' +import { clearHomeFilters } from '../../redux/slices' const initialCardsAmount = determineCardsAmountByViewport() @@ -37,9 +37,13 @@ function HomeContent() { dispatch(requestHomeCardsData(filters, 1, cardsAmount)) }, [cardsAmount, dispatch, filters]) + useEffect(() => { + dispatch(clearHomeFilters()) + }, [dispatch]) + return ( - +
- +
) } diff --git a/src/Pages/HomePage/HomeMenu.tsx b/src/Pages/HomePage/HomeMenu.tsx index 4e68f1a..65b8e65 100644 --- a/src/Pages/HomePage/HomeMenu.tsx +++ b/src/Pages/HomePage/HomeMenu.tsx @@ -2,13 +2,14 @@ import { useContext, useState } from 'react' import { useDispatch } from 'react-redux' import { Menu } from 'antd' import Sider from 'antd/es/layout/Sider' +import { Header } from 'antd/es/layout/layout' import { clearHomeFilters, setGenreToHomeFilters, setRatingToHomeFilters, } from '../../redux/slices' -import { ThemeContext, ratings } from '../../shared' +import { ThemeContext, SizeContext, ratings } from '../../shared' import { GenresError, GenresLoading } from '../../components' import { useTypedSelector } from '../../hooks' @@ -19,9 +20,10 @@ function HomeMenu() { const isError = useTypedSelector((state) => state.genres.isError) const genres = useTypedSelector((state) => state.genres.genres) const isLightTheme = useContext(ThemeContext) - const [openKeys, setOpenKeys] = useState(['rating']) - const dispatch = useDispatch() + const isNarrowScreen = useContext(SizeContext) + const [openKeys, setOpenKeys] = useState(isNarrowScreen ? [] : ['rating']) + const dispatch = useDispatch() const onOpenChange = (keys: string[]) => { const latestOpenKey = keys.find((key) => openKeys.indexOf(key) === -1) if (latestOpenKey && rootSubmenuKeys.indexOf(latestOpenKey) === -1) { @@ -60,27 +62,54 @@ function HomeMenu() { } return ( - - - No filters - - {ratings.map((item) => ( - {item.label} - ))} - - - {content} - - - + <> + {!isNarrowScreen && ( + + + No filters + + {ratings.map((item) => ( + {item.label} + ))} + + + {content} + + + + )} + {isNarrowScreen && ( +
+ + No filters + + {ratings.map((item) => ( + {item.label} + ))} + + + {content} + + +
+ )} + ) } diff --git a/src/Pages/ListsPage/ListsContent.tsx b/src/Pages/ListsPage/ListsContent.tsx index 869fde5..91ab7be 100644 --- a/src/Pages/ListsPage/ListsContent.tsx +++ b/src/Pages/ListsPage/ListsContent.tsx @@ -1,6 +1,8 @@ import { Content } from 'antd/es/layout/layout' import { Button, Flex, Input, Modal, Pagination, QRCode } from 'antd' import { useState, useCallback, useMemo, useLayoutEffect } from 'react' +import { useDispatch } from 'react-redux' +import { useParams } from 'react-router' import { CaseComponent, @@ -12,9 +14,7 @@ import { import { useTypedSelector, usePageResize } from '../../hooks' import { createListShareUrl, determineCardsAmountByViewport } from '../../utils' import { requestListAnimeData } from '../../redux/slices' -import { useDispatch } from 'react-redux' import { DispatchType } from '../../types' -import { useParams } from 'react-router' import { copyLinkToClipboard } from '../../utils/copyLinkToClipboard' const initialCardsAmount = determineCardsAmountByViewport() @@ -67,13 +67,7 @@ export function ListsContent() { usePageResize(onResize) return ( - + } emptyElement={} > - +
{listAnimes.map((anime) => ( ))} - +
state.lists.lists) const [newListName, setNewListName] = useState('') const [listNames, setListNames] = useState(['add']) @@ -38,7 +40,7 @@ function ListsMenu() { setListNames(['add', ...Object.keys(storedLists)]) }, [storedLists]) - useLayoutEffect(() => { + useEffect(() => { const items: { key: string; label: JSX.Element }[] = listNames.map( (item) => { const obj = { key: item, label:
} @@ -152,16 +154,91 @@ function ListsMenu() { setClickedDeleteList(null) }} /> - - - + {!isNarrowScreen && ( + + + + )} + {isNarrowScreen && ( +
+