Ver Fonte

create modal component

AykutSarac há 3 anos atrás
pai
commit
cc77dde5dd
2 ficheiros alterados com 100 adições e 89 exclusões
  1. 50 89
      src/components/Modal/index.tsx
  2. 50 0
      src/components/Modal/styles.tsx

+ 50 - 89
src/components/Modal/index.tsx

@@ -1,103 +1,64 @@
 import React from "react";
-import styled, { DefaultTheme } from "styled-components";
-import toast from "react-hot-toast";
+import { ReactComponent } from "src/typings/global";
+import { Button } from "src/components/Button";
+import * as Styled from "./styles";
 
-import { useConfig } from "src/hocs/config";
-import { ConfigActionType } from "src/reducer/reducer";
+type ControlProps = React.PropsWithChildren<{
+  setVisible: (status: boolean) => void;
+}>;
 
-enum ButtonType {
-  PRIMARY = "PRIMARY",
-  SECONDARY = "BLURPLE",
-  DANGER = "DANGER",
-  SUCCESS = "SEAGREEN",
-  WARNING = "ORANGE",
-}
+type ModalTypes = {
+  Header: ReactComponent;
+  Content: ReactComponent;
+  Controls: React.FC<ControlProps>;
+};
 
-function getButtonStatus(status: keyof typeof ButtonType, theme: DefaultTheme) {
-  return theme[ButtonType[status]];
+interface ModalProps {
+  visible: boolean;
+  setVisible: React.Dispatch<React.SetStateAction<boolean>>;
 }
 
-const StyledModalWrapper = styled.div`
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(0, 0, 0, 0.5);
-  z-index: 5;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-`;
-
-const StyledInput = styled.input`
-  background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
-  color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
-  outline: none;
-  border: none;
-  border-radius: 5px;
-  padding: 10px;
-  margin: 10px 0;
-  display: block;
-  width: 100%;
-`;
-
-const StyledButton = styled.button<{ status: keyof typeof ButtonType }>`
-  background: ${({ status, theme }) => getButtonStatus(status, theme)};
-  color: #ffffff;
-  padding: 8px 16px;
-  min-width: 60px;
-  margin-right: 10px;
-
-  @media only screen and (max-width: 768px) {
-    font-size: 18px;
-  }
-`;
-
-export const Modal = ({ visible, setVisible }) => {
-  const { json, settings, dispatch } = useConfig();
-  const inputRef = React.useRef<HTMLInputElement | null>(null);
+const Header: ReactComponent = ({ children }) => {
+  return (
+    <Styled.HeaderWrapper>
+      <Styled.Title>{children}</Styled.Title>
+    </Styled.HeaderWrapper>
+  );
+};
 
-  const fetchJSON = () => {
-    fetch(inputRef.current!.value)
-      .then((res) => res.json())
-      .then((json) => {
-        dispatch({
-          type: ConfigActionType.SET_JSON,
-          payload: JSON.stringify(json),
-        });
+const Content: ReactComponent = ({ children }) => {
+  return <Styled.ContentWrapper>{children}</Styled.ContentWrapper>;
+};
 
-        setVisible(false);
-      })
-      .catch((err) => toast.error(err.message));
-  };
+const Controls: React.FC<ControlProps> = ({ children, setVisible }) => {
+  return (
+    <Styled.ControlsWrapper>
+      <Button onClick={() => setVisible(false)}>Close</Button>
+      {children}
+    </Styled.ControlsWrapper>
+  );
+};
 
-  const cancel = () => {
-    setVisible(false);
+const Modal: React.FC<React.PropsWithChildren<ModalProps>> & ModalTypes = ({
+  children,
+  visible,
+  setVisible,
+}) => {
+  const onClick = (e: React.SyntheticEvent<HTMLDivElement>) => {
+    if (e.currentTarget === e.target) {
+      setVisible((v) => !v);
+    }
   };
 
   return (
-    visible && (
-      <StyledModalWrapper>
-        <div>
-          <h2>Import JSON from URL</h2>
-
-          <div>
-            <StyledInput
-              ref={inputRef}
-              type="url"
-              placeholder="URL of JSON to fetch"
-            />
-
-            <StyledButton status="PRIMARY" onClick={fetchJSON}>
-              Import
-            </StyledButton>
-            <StyledButton status="DANGER" onClick={cancel}>
-              Cancel
-            </StyledButton>
-          </div>
-        </div>
-      </StyledModalWrapper>
-    )
+    <Styled.ModalWrapper visible={visible} onClick={onClick}>
+      <Styled.ModalInnerWrapper>{children}</Styled.ModalInnerWrapper>
+    </Styled.ModalWrapper>
   );
 };
+
+Modal.Header = Header;
+Modal.Content = Content;
+Modal.Controls = Controls;
+
+export { Modal };

+ 50 - 0
src/components/Modal/styles.tsx

@@ -0,0 +1,50 @@
+import styled from "styled-components";
+
+export const ModalWrapper = styled.div<{ visible: boolean }>`
+  position: fixed;
+  top: 0;
+  left: 0;
+  height: 100vh;
+  width: 100%;
+  display: ${({ visible }) => (visible ? "flex" : "none")};
+  justify-content: center;
+  align-items: center;
+  background: rgba(0, 0, 0, 0.85);
+  z-index: 6;
+
+  * {
+    box-sizing: border-box;
+  }
+`;
+
+export const ModalInnerWrapper = styled.div`
+  min-width: 40vw;
+`;
+
+export const Title = styled.h2`
+  color: ${({ theme }) => theme.TEXT_NORMAL};
+  font-size: 20px !important;
+  margin: 0;
+`;
+
+export const HeaderWrapper = styled.div`
+  background: ${({ theme }) => theme.MODAL_BACKGROUND};
+  padding: 16px;
+  border-radius: 5px 5px 0 0;
+`;
+
+export const ContentWrapper = styled.div`
+  color: ${({ theme }) => theme.TEXT_NORMAL};
+  background: ${({ theme }) => theme.MODAL_BACKGROUND};
+  padding: 16px;
+  overflow: hidden scroll;
+`;
+
+export const ControlsWrapper = styled.div`
+  display: flex;
+  flex-direction: row-reverse;
+  background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
+  padding: 16px;
+  border-radius: 0 0 5px 5px;
+  gap: 10px;
+`;