diff --git a/components/domains/Emoji/Emojis.tsx b/components/domains/Emoji/Emojis.tsx
index 608785c..d9042fc 100644
--- a/components/domains/Emoji/Emojis.tsx
+++ b/components/domains/Emoji/Emojis.tsx
@@ -1,6 +1,7 @@
import { motion } from "framer-motion";
import { useRecoilValue } from "recoil";
import { Book, Heart, MirrorBall, Note } from "~/assets/svgs";
+import { useLayoutWidth } from "~/components/uis/Layout";
import { emojiAtomState } from "~/store/emoji";
const Emojis = ({ stage }: { stage: 1 | 2 | 3 }) => {
@@ -19,9 +20,11 @@ export default Emojis;
export const EmojiScaled = ({ stage }: { stage: 1 | 2 | 3 }) => {
const emoji = useRecoilValue(emojiAtomState);
- const getRandomHalfToFull = () => Math.random() / 4 + 3 / 4;
+ const getRandom3QuarterToFull = () => Math.random() / 4 + 3 / 4;
const randomMinus = Math.random() > 0.5 ? 1 : -1;
+ const { width } = useLayoutWidth();
+
const EmojiSVG = emoji
? emoji.emojiType === "HEART"
? Heart
@@ -40,16 +43,16 @@ export const EmojiScaled = ({ stage }: { stage: 1 | 2 | 3 }) => {
marginBottom: stage === 3 ? 140 : 1,
}}
initial={{
- x: (randomMinus * window.innerWidth * Math.random()) / 2,
- y: 400 * getRandomHalfToFull(),
+ x: (randomMinus * width * Math.random()) / 2,
+ y: 400 * getRandom3QuarterToFull(),
}}
animate={{
- x: (randomMinus * window.innerWidth * Math.random()) / 2,
- y: -2000 * getRandomHalfToFull(),
+ x: (randomMinus * width * Math.random()) / 2,
+ y: -2000 * getRandom3QuarterToFull(),
opacity: Math.random() * 0.9 + 0.1,
}}
- transition={{ duration: 3 * getRandomHalfToFull() }}
+ transition={{ duration: 3 * getRandom3QuarterToFull() }}
>
diff --git a/components/uis/Layout/index.tsx b/components/uis/Layout/index.tsx
index ca706ea..724f466 100644
--- a/components/uis/Layout/index.tsx
+++ b/components/uis/Layout/index.tsx
@@ -1,45 +1,58 @@
-import React from "react";
-import styled from "@emotion/styled";
+import React, { createContext, useContext } from "react";
+import { css } from "@emotion/react";
+import { useElementSize } from "~/hooks/commons";
+
+const Context = createContext({ width: 450 });
+export const useLayoutWidth = () => useContext(Context);
interface Props {
children: React.ReactNode;
screenColor?: string;
}
-function Layout({ children, screenColor = "#000000" }: Props) {
- return (
-
- {children}
-
- );
-}
+const Layout = ({ children, screenColor = "#000000" }: Props) => {
+ const [ref, size] = useElementSize();
-const S = {
- Container: styled.div`
- height: 100%;
- width: 100%;
- max-height: 100%;
- z-index: 100;
- display: flex;
- justify-content: center;
- `,
-
- Screen: styled.div<{ screenColor?: string }>`
- max-width: 450px;
- width: 100%;
- height: 100%;
- overflow-y: auto;
- overflow-x: hidden;
- background: ${(p) => p.screenColor};
- color: #fff;
- position: relative;
- backdrop-filter: blur(10px);
+ return (
+
+
+
+ );
};
export default Layout;
diff --git a/hooks/commons/index.ts b/hooks/commons/index.ts
index d195135..f41d473 100644
--- a/hooks/commons/index.ts
+++ b/hooks/commons/index.ts
@@ -8,3 +8,5 @@ export { default as useLongPress } from "./useLongPress";
export { default as useDisclosure } from "./useDisclosure";
export { default as useThrottle } from "./useThrottle";
export { default as useIsMobile } from "./useIsMobile";
+export { default as useElementSize } from "./useElementSize";
+export { default as useEventListener } from "./useEventListener";
diff --git a/hooks/commons/useElementSize/index.ts b/hooks/commons/useElementSize/index.ts
new file mode 100644
index 0000000..f4acf07
--- /dev/null
+++ b/hooks/commons/useElementSize/index.ts
@@ -0,0 +1,36 @@
+import { useCallback, useState } from "react";
+import useEventListener from "../useEventListener";
+import useIsomorphicLayoutEffect from "../useIsomorphicLayoutEffect";
+
+interface Size {
+ width: number;
+ height: number;
+}
+
+function useElementSize(): [
+ (node: T | null) => void,
+ Size
+] {
+ const [ref, setRef] = useState(null);
+ const [size, setSize] = useState({
+ width: 0,
+ height: 0,
+ });
+
+ const handleSize = useCallback(() => {
+ setSize({
+ width: ref?.offsetWidth || 0,
+ height: ref?.offsetHeight || 0,
+ });
+ }, [ref?.offsetHeight, ref?.offsetWidth]);
+
+ useEventListener("resize", handleSize);
+
+ useIsomorphicLayoutEffect(() => {
+ handleSize();
+ }, [ref?.offsetHeight, ref?.offsetWidth]);
+
+ return [setRef, size];
+}
+
+export default useElementSize;
diff --git a/hooks/commons/useEventListener/index.ts b/hooks/commons/useEventListener/index.ts
new file mode 100644
index 0000000..7c590ae
--- /dev/null
+++ b/hooks/commons/useEventListener/index.ts
@@ -0,0 +1,64 @@
+import type { RefObject } from "react";
+import { useEffect, useRef } from "react";
+import useIsomorphicLayoutEffect from "../useIsomorphicLayoutEffect";
+
+function useEventListener(
+ eventName: K,
+ handler: (event: WindowEventMap[K]) => void,
+ element?: undefined,
+ options?: boolean | AddEventListenerOptions
+): void;
+
+function useEventListener<
+ K extends keyof HTMLElementEventMap,
+ T extends HTMLElement = HTMLDivElement
+>(
+ eventName: K,
+ handler: (event: HTMLElementEventMap[K]) => void,
+ element: RefObject,
+ options?: boolean | AddEventListenerOptions
+): void;
+
+function useEventListener(
+ eventName: K,
+ handler: (event: DocumentEventMap[K]) => void,
+ element: RefObject,
+ options?: boolean | AddEventListenerOptions
+): void;
+
+function useEventListener<
+ KW extends keyof WindowEventMap,
+ KH extends keyof HTMLElementEventMap,
+ T extends HTMLElement | void = void
+>(
+ eventName: KW | KH,
+ handler: (
+ event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event
+ ) => void,
+ element?: RefObject,
+ options?: boolean | AddEventListenerOptions
+) {
+ const savedHandler = useRef(handler);
+
+ useIsomorphicLayoutEffect(() => {
+ savedHandler.current = handler;
+ }, [handler]);
+
+ useEffect(() => {
+ const targetElement: T | Window = element?.current || window;
+ if (!(targetElement && targetElement.addEventListener)) {
+ return;
+ }
+
+ const eventListener: typeof handler = (event) =>
+ savedHandler.current(event);
+
+ targetElement.addEventListener(eventName, eventListener, options);
+
+ return () => {
+ targetElement.removeEventListener(eventName, eventListener);
+ };
+ }, [eventName, element, options]);
+}
+
+export default useEventListener;