diff --git a/src/containers/dialogs/ExampleDialog/index.tsx b/src/containers/dialogs/ExampleDialog/index.tsx new file mode 100644 index 00000000..0ff75375 --- /dev/null +++ b/src/containers/dialogs/ExampleDialog/index.tsx @@ -0,0 +1,16 @@ +import React, { FC } from "react"; +import { ScrollDialog } from "../ScrollDialog"; + +interface IProps {} + +const ExampleDialog: FC = ({}) => { + const title =
title
; + const buttons =
buttons
; + return ( + +
test
+
+ ); +}; + +export { ExampleDialog }; diff --git a/src/containers/dialogs/ScrollDialog/index.tsx b/src/containers/dialogs/ScrollDialog/index.tsx new file mode 100644 index 00000000..06824c34 --- /dev/null +++ b/src/containers/dialogs/ScrollDialog/index.tsx @@ -0,0 +1,117 @@ +import React, { FC, MouseEventHandler, ReactChild, useCallback, useEffect, useState } from "react"; +// import { DialogPanel } from '~/components/panels/DialogPanel'; +import { Scroll } from "~/components/containers/Scroll"; +import * as styles from "./styles.scss"; +import classNames from "classnames"; + +interface IProps { + children: React.ReactChild; + title?: JSX.Element; + buttons?: JSX.Element; + size?: "medium" | "big"; + width?: number; + onOverlayClick?: MouseEventHandler; + onRefCapture?: (ref: any) => void; + + top_sticky?: ReactChild; + top_sticky_offset?: number; +} + +const ScrollDialog: FC = ({ + children, + title, + buttons, + size = "medium", + width = 800, + top_sticky, + top_sticky_offset, + + onOverlayClick, + onRefCapture +}) => { + const [height, setHeight] = useState(window.innerHeight - 240); + const [show_top_sticky, setShowTopSticky] = useState(false); + const [ref, setRef] = useState(null); + + const onResize = useCallback(() => setHeight(window.innerHeight - 240), []); + + useEffect(() => { + window.addEventListener("resize", onResize); + return () => window.removeEventListener("resize", onResize); + }, []); + + const onScroll = useCallback( + ({ target: { scrollTop = 0 } = {} } = {}) => { + if (!top_sticky || (!top_sticky_offset && top_sticky_offset !== 0)) return; + + const is_shown = scrollTop >= top_sticky_offset + 20; + + if (show_top_sticky !== is_shown) setShowTopSticky(is_shown); + }, + [top_sticky, top_sticky_offset, show_top_sticky, setShowTopSticky] + ); + + useEffect(() => onScroll(), []); + useEffect(() => { + if (ref && onRefCapture) onRefCapture(ref); + }, [ref, onRefCapture]); + + return ( +
+
+
+ + {!!title && ( +
+
+
+ {title} + {show_top_sticky && top_sticky && ( +
{top_sticky}
+ )} +
+
+
+ )} + + {!!buttons && ( +
+
+
{buttons}
+
+
+ )} + +
+ +
+
{children}
+
+
+
+
+
+ ); +}; + +export { ScrollDialog }; diff --git a/src/containers/dialogs/ScrollDialog/styles.scss b/src/containers/dialogs/ScrollDialog/styles.scss new file mode 100644 index 00000000..a90d3400 --- /dev/null +++ b/src/containers/dialogs/ScrollDialog/styles.scss @@ -0,0 +1,97 @@ +.container { + height: 100vh; + width: 100%; + align-items: center; + justify-content: center; + display: flex; + position: relative; +} + +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.content { + display: flex; + align-items: center; + justify-content: center; + position: relative; + padding: 0; + box-sizing: border-box; + flex: 1 1 800px; + z-index: 1; + + &:global(.has_title) { + padding-top: 64px + 15px; // +15px + } + + &:global(.has_buttons) { + padding-bottom: 64px + 15px; // +15px + } +} + +.top, +.bottom { + width: 100%; + height: 64px; + position: absolute; + top: 20px; + bottom: auto; + left: 0; + display: flex; + align-items: center; + justify-content: center; + padding: 0 $gap; + box-sizing: border-box; + z-index: 2; +} + +.bottom { + bottom: 20px; + top: auto; + + .pan { + border-radius: 0 0 $radius $radius; + } +} + +.wrap { + flex: 0 1 800px; + height: 100%; +} + +.scroll_wrap { + flex: 0 1 840px; + height: 100%; +} + +.content_wrap { + padding: 0 20px; +} + +.top_sticky { + position: absolute; + top: 100%; + left: 0; + width: 100%; + padding-top: $gap * 2; + margin-top: -$gap; + z-index: -1; + background: transparentize(white, 0.1); + border-radius: $radius; + box-shadow: transparentize(black, 0.9) 0 15px 15px; +} + +.pan { + background: darken($content_bg, 4%); + height: 64px; +} + +.children { + background: $content_bg; + radius: $radius; +} diff --git a/src/redux/modal/constants.ts b/src/redux/modal/constants.ts index 2ae647d7..8bc6f91a 100644 --- a/src/redux/modal/constants.ts +++ b/src/redux/modal/constants.ts @@ -1,5 +1,6 @@ import { ValueOf } from "~/redux/types"; import { HorizontalExample } from "~/containers/examples/HorizontalExample"; +import { ExampleDialog } from "~/containers/dialogs/ExampleDialog"; export const MODAL_ACTIONS = { SET_SHOWN: "MODAL.SET_SHOWN", @@ -12,7 +13,7 @@ export const DIALOGS = { }; export const DIALOG_CONTENT = { - [DIALOGS.TEST]: HorizontalExample + [DIALOGS.TEST]: ExampleDialog }; export interface IDialogProps { diff --git a/src/redux/modal/reducer.ts b/src/redux/modal/reducer.ts index 148bcd83..9fd3de2c 100644 --- a/src/redux/modal/reducer.ts +++ b/src/redux/modal/reducer.ts @@ -9,7 +9,7 @@ export interface IModalState { } const INITIAL_STATE: IModalState = { - is_shown: false, + is_shown: true, dialog: DIALOGS.TEST };