Skip to content
This repository has been archived by the owner on Nov 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #20 from claustra01/shooter_modal
Browse files Browse the repository at this point in the history
Add: スマホを画面に向かって垂直に机の上に置いてねモーダルの実装
  • Loading branch information
K-Kizuku authored Aug 10, 2024
2 parents 325caba + 31a4070 commit 6eead73
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 7 deletions.
Binary file added public/2D_material/modal.webp
Binary file not shown.
21 changes: 21 additions & 0 deletions src/components/ui/Modal/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.modal-background{
background-color:#08000080;
width:100%;
height:100%;
position:fixed;
left:0;
top:0;
z-index:0;

}

.modal-content-wrapper{
position:absolute;
left:50%;
top:30%;
translate: -50% -50%;
z-index:10;
border: none;
border-radius: 8px;
overflow: hidden;
}
81 changes: 81 additions & 0 deletions src/components/ui/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useCallback, useEffect, useRef } from "react";
import type { FC, ReactNode } from "react";
import { createPortal } from "react-dom";
import styles from "./index.module.css";

type Props = {
open: boolean;
children: ReactNode;
onClose?: () => void;
onOpen?: () => void;
};

export const Modal: FC<Props> = ({
children,
open,
onClose = () => {},
onOpen = () => {},
}) => {
const dialogRef = useRef<HTMLDialogElement>(null);

const handleShowModal = useCallback(() => {
onOpen();
dialogRef.current?.showModal();
}, [onOpen]);

const handleCloseModal = useCallback(() => {
onClose();
dialogRef.current?.close();
}, [onClose]);

useEffect(() => {
if (open) {
handleShowModal();
} else {
handleCloseModal();
}
}, [open, handleShowModal, handleCloseModal]);

const handleKeyUp = useCallback(
(event: KeyboardEvent) => {
if (event.key === "Escape") {
handleCloseModal();
}
},
[handleCloseModal],
);

useEffect(() => {
if (open) {
document.addEventListener("keyup", handleKeyUp);
} else {
document.removeEventListener("keyup", handleKeyUp);
}
return () => {
document.removeEventListener("keyup", handleKeyUp);
};
}, [open, handleKeyUp]);

return createPortal(
<>
<dialog
ref={dialogRef}
className={styles["modal-content-wrapper"]}
onKeyDown={(e) => e.key === "Enter" && handleShowModal()}
tabIndex={-1}
>
{children}
</dialog>
{open && (
<button
type="button"
className={styles["modal-background"]}
onClick={handleCloseModal}
onKeyDown={(e) => e.key === "Enter" && handleCloseModal()}
aria-label="Close modal"
/>
)}
</>,
document.body,
);
};
39 changes: 38 additions & 1 deletion src/pages/shooter/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,41 @@
.cork img {
width: 72px;
height: 72px;
}
}
.button-style {
position: absolute;
bottom: 6%;
right: 4%;
}

.modal-wrapper {
padding: 24px 0;
border-radius: 8px;
background-color: white;
min-width: 320px;
display: flex;
flex-direction: column;
gap: 24px;
justify-content: center;
align-items: center;
}

.modal-description {
font-size: 18px;
padding: 0 36px;
text-align: center;
}

.modal-selection-wrapper {
display: flex;
width: 100%;
flex-direction: row;
gap: 16px;
justify-content: center;
}

.modal-row {
display: flex;
align-items: center;
justify-content: center;
}
48 changes: 42 additions & 6 deletions src/pages/shooter/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { type KeyboardEventHandler, useState } from "react";
import { DefaultButton } from "../../components/ui/Button";
import { Modal } from "../../components/ui/Modal";
import { ShooterButton } from "../../components/ui/ShooterButton";
import style from "./index.module.css";

function Shooter() {
const [isOpen, setIsOpen] = useState(true);

const initialImages = [
"/2D_material/cork.webp",
"/2D_material/cork.webp",
Expand All @@ -23,13 +27,11 @@ function Shooter() {

return (
<div>
<Modal open={isOpen} onClose={() => setIsOpen(false)}>
<ModalContent setIsOpen={setIsOpen} />
</Modal>
<div className={style.trigger}>
<ShooterButton
onClick={handleClick}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyUp}
onKeyPress={handleKeyUp}
/>
<ShooterButton onClick={handleClick} onKeyUp={handleKeyUp} />
</div>
<div className={style.cork}>
{images.map((src) => (
Expand All @@ -40,4 +42,38 @@ function Shooter() {
);
}

type ModalContentProps = {
setIsOpen: (isOpen: boolean) => void;
};

const ModalContent: React.FC<ModalContentProps> = ({ setIsOpen }) => {
return (
<div className={style["modal-wrapper"]}>
<img
src="/2D_material/modal.webp"
alt="スマホを画面に向かって垂直におく図"
width="100"
height="100"
/>
<div className={style["modal-row"]}>
<p className={style["modal-description"]}>
スマホを画面に向かって
<br />
垂直に机の上に置いてね
</p>
</div>
<div className={style["modal-selection-wrapper"]}>
<DefaultButton
variant="outlined"
color="red"
size="md"
onClick={() => setIsOpen(false)}
>
置いたよ!
</DefaultButton>
</div>
</div>
);
};

export default Shooter;

0 comments on commit 6eead73

Please sign in to comment.