diff --git a/package-lock.json b/package-lock.json
index 9b870a7..20524a4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,6 +17,7 @@
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
"react": "^18.2.0",
+ "react-device-detect": "^2.2.3",
"react-dom": "^18.2.0",
"react-i18next": "^11.18.3",
"react-redux": "^7.2.6",
@@ -22735,6 +22736,18 @@
"react-dom": ">=16.8.0"
}
},
+ "node_modules/react-device-detect": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz",
+ "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==",
+ "dependencies": {
+ "ua-parser-js": "^1.0.33"
+ },
+ "peerDependencies": {
+ "react": ">= 0.14.0",
+ "react-dom": ">= 0.14.0"
+ }
+ },
"node_modules/react-docgen": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz",
@@ -26164,6 +26177,28 @@
"node": ">=4.2.0"
}
},
+ "node_modules/ua-parser-js": {
+ "version": "1.0.37",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
+ "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/faisalman"
+ }
+ ],
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -43243,6 +43278,14 @@
"dev": true,
"requires": {}
},
+ "react-device-detect": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz",
+ "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==",
+ "requires": {
+ "ua-parser-js": "^1.0.33"
+ }
+ },
"react-docgen": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz",
@@ -45757,6 +45800,11 @@
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true
},
+ "ua-parser-js": {
+ "version": "1.0.37",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
+ "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ=="
+ },
"uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
diff --git a/package.json b/package.json
index 7914129..7981215 100644
--- a/package.json
+++ b/package.json
@@ -110,6 +110,7 @@
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
"react": "^18.2.0",
+ "react-device-detect": "^2.2.3",
"react-dom": "^18.2.0",
"react-i18next": "^11.18.3",
"react-redux": "^7.2.6",
diff --git a/src/features/notificationButton/ui/NotificationButton/NotificationButton.tsx b/src/features/notificationButton/ui/NotificationButton/NotificationButton.tsx
index 07814b9..f72e2e9 100644
--- a/src/features/notificationButton/ui/NotificationButton/NotificationButton.tsx
+++ b/src/features/notificationButton/ui/NotificationButton/NotificationButton.tsx
@@ -1,30 +1,53 @@
-import { classNames } from 'shared/lib/classNames/classNames';
-import React, { memo } from 'react';
-import { Button, ButtonTheme } from 'shared/ui/Button/Button';
-import { Icon } from 'shared/ui/Icon/Icon';
-import NotificationIcon from 'shared/assets/icons/notification-20-20.svg';
-import { NotificationList } from 'entities/Notification';
-import { Popover } from 'shared/ui/Popups';
-import cls from './NotificationButton.module.scss';
+import { classNames } from "shared/lib/classNames/classNames";
+import React, { memo, useCallback, useState } from "react";
+import { Button, ButtonTheme } from "shared/ui/Button/Button";
+import { Icon } from "shared/ui/Icon/Icon";
+import NotificationIcon from "shared/assets/icons/notification-20-20.svg";
+import { NotificationList } from "entities/Notification";
+import { Popover } from "shared/ui/Popups";
+import { Drawer } from "shared/ui/Drawer/Drawer";
+import { BrowserView, MobileView } from "react-device-detect";
+import cls from "./NotificationButton.module.scss";
interface NotificationButtonProps {
- className?: string;
+ className?: string;
}
export const NotificationButton = memo((props: NotificationButtonProps) => {
- const { className } = props;
+ const { className } = props;
+ const [isOpen, setIsOpen] = useState(false);
- return (
+ const onOpenDrawer = useCallback(() => {
+ setIsOpen(true);
+ }, []);
+
+ const onCloseDrawer = useCallback(() => {
+ setIsOpen(false);
+ }, []);
+
+ const trigger = (
+
+ );
+
+ return (
+
+
-
-
- )}
+ className={classNames(cls.NotificationButton, {}, [className])}
+ direction="bottom left"
+ trigger={trigger}
>
-
+
- );
+
+
+ {trigger}
+
+
+
+
+
+ );
});
diff --git a/src/shared/ui/Drawer/Drawer.module.scss b/src/shared/ui/Drawer/Drawer.module.scss
new file mode 100644
index 0000000..e440393
--- /dev/null
+++ b/src/shared/ui/Drawer/Drawer.module.scss
@@ -0,0 +1,51 @@
+.Drawer {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ opacity: 0;
+ pointer-events: none;
+ z-index: -1;
+ display: flex;
+ align-items: flex-end;
+}
+
+.content {
+ height: 70%;
+ background: var(--bg-color);
+ bottom: 0;
+ border-top-left-radius: 12px;
+ border-top-right-radius: 12px;
+ position: relative;
+ width: 100%;
+ min-height: 100px;
+ padding: 20px;
+ transition: 0.3s transform;
+ transform: translateY(100%);
+ overflow-y: auto;
+ overflow-x: hidden;
+ z-index: 10000;
+}
+
+.content::before {
+ content: "";
+ position: relative;
+ display: block;
+ width: 100px;
+ height: 10px;
+ background: var(--bg-color);
+ margin: auto;
+ bottom: 40px;
+ border-radius: 12px;
+}
+
+.opened {
+ pointer-events: auto;
+ opacity: 1;
+ z-index: var(--modal-z-index);
+
+ .content {
+ transform: translateY(0%);
+ }
+}
diff --git a/src/shared/ui/Drawer/Drawer.tsx b/src/shared/ui/Drawer/Drawer.tsx
new file mode 100644
index 0000000..16b3114
--- /dev/null
+++ b/src/shared/ui/Drawer/Drawer.tsx
@@ -0,0 +1,40 @@
+import { classNames, Mods } from 'shared/lib/classNames/classNames';
+import React, { memo, ReactNode } from 'react';
+import { useTheme } from 'app/providers/ThemeProvider';
+import { Overlay } from '../Overlay/Overlay';
+import cls from './Drawer.module.scss';
+import { Portal } from '../Portal/Portal';
+
+interface DrawerProps {
+ className?: string;
+ children: ReactNode;
+ isOpen?: boolean;
+ onClose?: () => void;
+}
+
+export const Drawer = memo((props: DrawerProps) => {
+ const {
+ className,
+ children,
+ onClose,
+ isOpen,
+ } = props;
+ const { theme } = useTheme();
+
+ const mods: Mods = {
+ [cls.opened]: isOpen,
+ };
+
+ return (
+
+
+
+ );
+});
diff --git a/src/shared/ui/Modal/Modal.module.scss b/src/shared/ui/Modal/Modal.module.scss
index bd7f84b..39cc79e 100644
--- a/src/shared/ui/Modal/Modal.module.scss
+++ b/src/shared/ui/Modal/Modal.module.scss
@@ -1,5 +1,8 @@
.Modal {
position: fixed;
+ display: flex;
+ justify-content: center;
+ align-items: center;
top: 0;
bottom: 0;
right: 0;
diff --git a/src/shared/ui/Modal/Modal.tsx b/src/shared/ui/Modal/Modal.tsx
index 441e3d8..73a2110 100644
--- a/src/shared/ui/Modal/Modal.tsx
+++ b/src/shared/ui/Modal/Modal.tsx
@@ -1,15 +1,17 @@
-import {classNames, Mods} from "shared/lib/classNames/classNames";
+import { classNames, Mods } from "shared/lib/classNames/classNames";
import {
ReactNode,
useCallback,
useEffect,
useRef,
useState,
- MouseEvent, MutableRefObject,
+ MouseEvent,
+ MutableRefObject,
} from "react";
import { Portal } from "../Portal/Portal";
import { useTheme } from "app/providers/ThemeProvider";
import cls from "./Modal.module.scss";
+import { Overlay } from "../Overlay/Overlay";
interface ModalProps {
className?: string;
@@ -84,10 +86,9 @@ export const Modal = (props: ModalProps) => {
-
-
- {children}
-
+
+
+ {children}
diff --git a/src/shared/ui/Overlay/Overlay.module.scss b/src/shared/ui/Overlay/Overlay.module.scss
new file mode 100644
index 0000000..ff7a032
--- /dev/null
+++ b/src/shared/ui/Overlay/Overlay.module.scss
@@ -0,0 +1,13 @@
+.Overlay {
+ background: var(--overlay-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ z-index: -1;
+ cursor: pointer;
+}
diff --git a/src/shared/ui/Overlay/Overlay.tsx b/src/shared/ui/Overlay/Overlay.tsx
new file mode 100644
index 0000000..aa3164f
--- /dev/null
+++ b/src/shared/ui/Overlay/Overlay.tsx
@@ -0,0 +1,16 @@
+import { classNames } from 'shared/lib/classNames/classNames';
+import { memo } from 'react';
+import cls from './Overlay.module.scss';
+
+interface OverlayProps {
+ className?: string;
+ onClick?: () => void;
+}
+
+export const Overlay = memo((props: OverlayProps) => {
+ const { className, onClick } = props;
+
+ return (
+
+ );
+});
diff --git a/src/shared/ui/Stack/VStack/VStack.tsx b/src/shared/ui/Stack/VStack/VStack.tsx
index a266628..94c6f7a 100644
--- a/src/shared/ui/Stack/VStack/VStack.tsx
+++ b/src/shared/ui/Stack/VStack/VStack.tsx
@@ -1,10 +1,8 @@
-import { Flex, FlexProps } from '../Flex/Flex';
+import { Flex, FlexProps } from "../Flex/Flex";
-type VStackProps = Omit
+type VStackProps = Omit;
export const VStack = (props: VStackProps) => {
- const { align = 'start' } = props;
- return (
-
- );
+ const { align = "start" } = props;
+ return ;
};
diff --git a/src/widgets/SideBar/ui/SideBar/SideBar.module.scss b/src/widgets/SideBar/ui/SideBar/SideBar.module.scss
index 297bd87..3bf782d 100644
--- a/src/widgets/SideBar/ui/SideBar/SideBar.module.scss
+++ b/src/widgets/SideBar/ui/SideBar/SideBar.module.scss
@@ -10,7 +10,7 @@
position: absolute;
right: -32px;
bottom: 32px;
- z-index: 100000;
+ z-index: 10;
}
.switchers {