mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-25 18:13:10 +03:00
feat(Filter/Popup): add responsive popup component
This commit is contained in:
parent
d3459a9919
commit
5233b5c056
@ -12,7 +12,7 @@ const STYLES_DATAVIEWER_WRAPPER = (theme) => css`
|
||||
min-height: 100vh;
|
||||
padding: calc(20px + ${theme.sizes.filterNavbar}px) 24px 44px;
|
||||
@media (max-width: ${theme.sizes.mobile}px) {
|
||||
padding: 31px 16px 44px;
|
||||
padding: calc(31px + ${theme.sizes.filterNavbar}px) 16px 44px;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import * as Styles from "~/common/styles";
|
||||
|
||||
import { usePortals } from "~/components/core/PortalsProvider";
|
||||
import { css } from "@emotion/react";
|
||||
@ -16,8 +17,9 @@ export function NavbarPortal({ children }) {
|
||||
return filterNavbarElement
|
||||
? ReactDOM.createPortal(
|
||||
<>
|
||||
<Divider height="0.5px" />
|
||||
<Divider height="0.5px" color="borderGrayLight" css={Styles.MOBILE_HIDDEN} />
|
||||
<div css={STYLES_NAVBAR}>{children}</div>
|
||||
<Divider height="0.5px" color="borderGrayLight" css={Styles.MOBILE_ONLY} />
|
||||
</>,
|
||||
filterNavbarElement
|
||||
)
|
||||
@ -29,12 +31,27 @@ export function NavbarPortal({ children }) {
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
|
||||
const STYLES_NAVBAR = (theme) => css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: ${theme.semantic.bgWhite};
|
||||
padding: 9px 24px 11px;
|
||||
box-shadow: ${theme.shadow.lightSmall};
|
||||
|
||||
@media (max-width: ${theme.sizes.mobile}px) {
|
||||
padding: 9px 16px 11px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_NAVBAR_BACKGROUND = (theme) => css`
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: -1;
|
||||
|
||||
background-color: ${theme.semantic.bgWhite};
|
||||
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
|
||||
-webkit-backdrop-filter: blur(75px);
|
||||
backdrop-filter: blur(75px);
|
||||
@ -49,5 +66,10 @@ const STYLES_NAVBAR = (theme) => css`
|
||||
export function Navbar({ children }) {
|
||||
const { filterNavbar } = usePortals();
|
||||
const [, setFilterElement] = filterNavbar;
|
||||
return <div ref={setFilterElement}>{children}</div>;
|
||||
return (
|
||||
<div ref={setFilterElement}>
|
||||
{children}
|
||||
<div css={STYLES_NAVBAR_BACKGROUND} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
80
components/core/Filter/Popup.js
Normal file
80
components/core/Filter/Popup.js
Normal file
@ -0,0 +1,80 @@
|
||||
import * as React from "react";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as Styles from "~/common/styles";
|
||||
import * as Filters from "~/components/core/Filter/Filters";
|
||||
|
||||
import { useFilterContext } from "~/components/core/Filter/Provider";
|
||||
import { motion } from "framer-motion";
|
||||
import { css } from "@emotion/react";
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Popup trigger
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function PopupTrigger({ children, isMobile, ...props }) {
|
||||
const [{ sidebarState, popupState }, { hidePopup, togglePopup }] = useFilterContext();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (sidebarState.isVisible) {
|
||||
hidePopup();
|
||||
}
|
||||
}, [sidebarState.isVisible]);
|
||||
|
||||
if (sidebarState.isVisible && !isMobile) return null;
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={togglePopup}
|
||||
css={[Styles.BUTTON_RESET, Styles.HORIZONTAL_CONTAINER_CENTERED]}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<motion.div initial={null} animate={{ rotateX: popupState.isVisible ? 180 : 0 }}>
|
||||
<SVG.ChevronUp style={{ display: "block" }} />
|
||||
</motion.div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Popup
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
const STYLES_SIDEBAR_FILTER_WRAPPER = (theme) => css`
|
||||
position: sticky;
|
||||
top: ${theme.sizes.header + theme.sizes.filterNavbar}px;
|
||||
width: 236px;
|
||||
max-height: 420px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border-radius: 16px;
|
||||
padding: 20px 16px;
|
||||
box-shadow: ${theme.shadow.lightLarge};
|
||||
border: 1px solid ${theme.semantic.borderGrayLight};
|
||||
|
||||
background-color: ${theme.semantic.bgLight};
|
||||
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
|
||||
background-color: ${theme.semantic.bgBlurWhite};
|
||||
-webkit-backdrop-filter: blur(75px);
|
||||
backdrop-filter: blur(75px);
|
||||
}
|
||||
|
||||
@media (max-width: ${theme.sizes.mobile}px) {
|
||||
border-radius: unset;
|
||||
width: 100%;
|
||||
max-height: 375px;
|
||||
padding: 15px 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
export function Popup({ viewer, css, ...props }) {
|
||||
const [{ popupState }] = useFilterContext();
|
||||
|
||||
if (!popupState.isVisible) return null;
|
||||
|
||||
return (
|
||||
<div css={[STYLES_SIDEBAR_FILTER_WRAPPER, css]} {...props}>
|
||||
<Filters.Library />
|
||||
<Filters.Tags viewer={viewer} style={{ marginTop: 12 }} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -4,14 +4,21 @@ import * as System from "~/components/system";
|
||||
import { Navbar, NavbarPortal } from "~/components/core/Filter/Navbar";
|
||||
import { Provider } from "~/components/core/Filter/Provider";
|
||||
import { Sidebar, SidebarTrigger } from "~/components/core/Filter/Sidebar";
|
||||
import { Popup, PopupTrigger } from "~/components/core/Filter/Popup";
|
||||
import { Content } from "~/components/core/Filter/Content";
|
||||
import { useFilterContext } from "~/components/core/Filter/Provider";
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Title
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Title() {
|
||||
return <System.H5 color="textBlack">All</System.H5>;
|
||||
const [{ filterState }] = useFilterContext();
|
||||
return (
|
||||
<System.H5 as="p" color="textBlack">
|
||||
{filterState.title}
|
||||
</System.H5>
|
||||
);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
@ -21,4 +28,15 @@ function Actions() {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
export { Title, Actions, Sidebar, SidebarTrigger, Provider, Navbar, Content, NavbarPortal };
|
||||
export {
|
||||
Title,
|
||||
Actions,
|
||||
Sidebar,
|
||||
SidebarTrigger,
|
||||
Popup,
|
||||
PopupTrigger,
|
||||
Provider,
|
||||
Navbar,
|
||||
Content,
|
||||
NavbarPortal,
|
||||
};
|
||||
|
@ -17,12 +17,24 @@ const STYLES_SCENE_PAGE = css`
|
||||
`;
|
||||
|
||||
const STYLES_FILTER_TITLE_WRAPPER = css`
|
||||
${Styles.MOBILE_HIDDEN};
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
`;
|
||||
|
||||
const STYLES_FILTER_POPUP_WRAPPER = (theme) => css`
|
||||
position: absolute;
|
||||
top: calc(${theme.sizes.filterNavbar}px + 4px);
|
||||
left: 4px;
|
||||
width: 100%;
|
||||
@media (max-width: ${theme.sizes.mobile}px) {
|
||||
top: ${theme.sizes.filterNavbar}px;
|
||||
left: 0px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function SceneFilesFolder({ viewer, page, onAction, isMobile }) {
|
||||
const [index, setIndex] = React.useState(-1);
|
||||
|
||||
@ -47,9 +59,21 @@ export default function SceneFilesFolder({ viewer, page, onAction, isMobile }) {
|
||||
/>
|
||||
<Filter.Provider viewer={viewer}>
|
||||
<Filter.NavbarPortal>
|
||||
<div css={Styles.CONTAINER_CENTERED}>
|
||||
<Filter.SidebarTrigger />
|
||||
<div css={STYLES_FILTER_POPUP_WRAPPER}>
|
||||
<Filter.Popup viewer={viewer} />
|
||||
</div>
|
||||
|
||||
<div css={Styles.CONTAINER_CENTERED}>
|
||||
<div css={Styles.MOBILE_HIDDEN}>
|
||||
<Filter.SidebarTrigger />
|
||||
</div>
|
||||
<Filter.PopupTrigger isMobile={isMobile} style={{ marginLeft: 2 }}>
|
||||
<span css={Styles.MOBILE_ONLY} style={{ marginRight: 8 }}>
|
||||
<Filter.Title />
|
||||
</span>
|
||||
</Filter.PopupTrigger>
|
||||
</div>
|
||||
|
||||
<div css={STYLES_FILTER_TITLE_WRAPPER}>
|
||||
<Filter.Title />
|
||||
</div>
|
||||
@ -57,7 +81,7 @@ export default function SceneFilesFolder({ viewer, page, onAction, isMobile }) {
|
||||
</Filter.NavbarPortal>
|
||||
|
||||
<div css={Styles.HORIZONTAL_CONTAINER}>
|
||||
<Filter.Sidebar />
|
||||
<Filter.Sidebar viewer={viewer} isMobile={isMobile} />
|
||||
<Filter.Content onAction={onAction} viewer={viewer} page={page} />
|
||||
</div>
|
||||
</Filter.Provider>
|
||||
|
Loading…
Reference in New Issue
Block a user