Skip to content

Commit

Permalink
feat: add a modal provider (#26)
Browse files Browse the repository at this point in the history
* feat: modal provider
* feat: add body size
  • Loading branch information
0xbulma authored Nov 3, 2023
1 parent b74b759 commit 4e60f51
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 25 deletions.
10 changes: 1 addition & 9 deletions front/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
30 changes: 30 additions & 0 deletions front/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}

html {
overflow-x: hidden;
background-color: #696E77;

}

body {
position: relative;
max-width: 390px;
min-height: 100svh;
margin: 0 auto;
overflow: hidden;

}

@media (min-width: 391px) {
body {
margin: 20px auto;
border-radius: 20px;
min-height: calc(100svh - 40px);
overflow: hidden;

}
}
13 changes: 5 additions & 8 deletions front/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import "@rainbow-me/rainbowkit/styles.css";
import "@radix-ui/themes/styles.css";
import "./globals.css";
import { Theme, ThemePanel } from "@radix-ui/themes";
import ThemeProvider from "@/components/ThemeProvider.tsx";
import ThemeProvider from "@/providers/ThemeProvider";
import { WalletConnectProvider } from "@/libs/wallet-connect";
import { SmartWalletProvider } from "@/libs/smart-wallet/SmartWalletProvider";
import { ModalProvider } from "@/providers/ModalProvider";

export const metadata = {
title: "HocusPocus XYZ",
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<SmartWalletProvider>
<WalletConnectProvider>
<ThemeProvider attribute="class">
<Theme>
{children}
<ModalProvider>{children}</ModalProvider>
{/* <ThemePanel /> */}
</Theme>
</ThemeProvider>
Expand Down
14 changes: 14 additions & 0 deletions front/src/components/Modal1/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Button } from "@radix-ui/themes";
import Modal2 from "../Modal2";
import { useModal } from "@/providers/ModalProvider";

export default function Modal1() {
const { open } = useModal();

return (
<div>
Modal1
<Button onClick={() => open(<Modal2 />)}>SHOW MODAL 2</Button>
</div>
);
}
3 changes: 3 additions & 0 deletions front/src/components/Modal2/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Modal2() {
return <div>Modal2</div>;
}
12 changes: 6 additions & 6 deletions front/src/components/WCInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import { useState } from "react";
import { Flex, TextField, Button } from "@radix-ui/themes";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { useWalletConnect } from "@/libs/wallet-connect";
import { useModal } from "@/providers/ModalProvider";
import Modal1 from "../Modal1";

export default function WCInput() {
const [input, setInput] = useState<string>("");

const { pairSession, pairingState } = useWalletConnect();
const { open } = useModal();

const isLoading = Object.values(pairingState).some(
(element) => element.isLoading
);
const isLoading = Object.values(pairingState).some((element) => element.isLoading);

return (
<Flex gap="2">
Expand All @@ -26,9 +27,8 @@ export default function WCInput() {
onChange={(e) => setInput(e.target.value)}
/>
</TextField.Root>
<Button onClick={() => pairSession(input)}>
{isLoading ? "is connecting" : "Connect"}
</Button>
<Button onClick={() => pairSession(input)}>{isLoading ? "is connecting" : "Connect"}</Button>
<Button onClick={() => open(<Modal1 />)}>SHOW MODAL</Button>
</Flex>
);
}
2 changes: 1 addition & 1 deletion front/src/libs/smart-wallet/SmartWalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const useWalletConnect = (): UseSmartWallet => {
const context = useContext(SmartWalletContext);
if (!context) {
throw new Error(
"useSmartWalletHook must be used within a WalletConnectProvider"
"useSmartWalletHook must be used within a SmartWalletProvider"
);
}
return context;
Expand Down
116 changes: 116 additions & 0 deletions front/src/providers/ModalProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"use client";

import React, { useContext, useEffect, useState } from "react";
import { Portal } from "@radix-ui/themes";
import styled from "@emotion/styled";

const PortalContainer = styled(Portal)<{ isOpen: Boolean }>`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100svh;
@media (min-width: 391px) {
height: calc(100vh - 40px);
}
pointer-events: ${({ isOpen }) => (isOpen ? "auto" : "none")};
`;

const Modal = styled.div<{ isOpen: Boolean }>`
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 80svh;
border: 5px solid var(--accent-9);
border-radius: 10px 10px 0 0;
background-color: white;
transform: ${({ isOpen }) => (isOpen ? "translate3d(0, 0, 0)" : "translate3d(0, 100svh, 0)")};
transition: transform 0.1s ease-in-out;
color: black;
`;

const Overlay = styled.div<{ isOpen: Boolean }>`
position: absolute;
top: 0;
left: 0;
opacity: ${({ isOpen }) => (isOpen ? 1 : 0)};
backdrop-filter: blur(3px);
// background-color: rgba(var(--color-selection-root), 0.5);
width: 100%;
height: 100svh;
@media (min-width: 391px) {
height: calc(100vh - 40px);
}
visibility: ${({ isOpen }) => (isOpen ? "visible" : "hidden")};
transition: opacity 0.1s ease-in-out;
`;

function useModalHook() {
const [content, setContent] = useState<React.ReactNode>(null);
const [isOpen, setIsOpen] = useState<Boolean>(false);
const [isBackdrop, setIsBackdrop] = useState<Boolean>(false);

function open(content: React.ReactNode) {
if (isOpen) {
setContent(null);
setIsOpen(false);
setTimeout(() => {
setContent(content);
setIsOpen(true);
}, 150);
return;
}

setContent(content);
setIsOpen(true);
setIsBackdrop(true);
}

function close() {
setContent(null);
setIsOpen(false);
setIsBackdrop(false);
}

return {
content,
isOpen,
isBackdrop,
open,
close,
};
}

type UseModalHook = ReturnType<typeof useModalHook>;
const ModalContext = React.createContext<UseModalHook | null>(null);

export const useModal = (): UseModalHook => {
const context = useContext(ModalContext);
if (!context) {
throw new Error("useModalHook must be used within a ModalHoolProvider");
}
return context;
};

export function ModalProvider({ children }: { children: React.ReactNode }) {
const modalValue = useModalHook();
const [isPortalMounted, setIsPortalMounted] = useState(false);

useEffect(() => {
setIsPortalMounted(true);
}, []);

const radixElement = document.getElementsByClassName("radix-themes")[0];
return (
<ModalContext.Provider value={modalValue}>
{children}
{isPortalMounted && (
<PortalContainer isOpen={modalValue.isOpen} container={radixElement as HTMLElement}>
<Overlay isOpen={modalValue.isBackdrop} onClick={() => modalValue.close()} />
<Modal isOpen={modalValue.isOpen}>{modalValue.content}</Modal>
</PortalContainer>
)}
</ModalContext.Provider>
);
}
File renamed without changes.
2 changes: 1 addition & 1 deletion front/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/providers/ThemeProvider"],
"exclude": ["node_modules"]
}

0 comments on commit 4e60f51

Please sign in to comment.