Skip to content

Commit

Permalink
Feat: #24 React Portal Modal Layout UI 작업
Browse files Browse the repository at this point in the history
  • Loading branch information
Seok93 committed Jun 21, 2024
1 parent 53dc5ff commit bf61c55
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 30 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</head>
<body>
<div id="root"></div>
<div id="modal"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Empty file removed src/components/common/.gitkeep
Empty file.
7 changes: 7 additions & 0 deletions src/components/common/ModalPortal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { PropsWithChildren } from 'react';
import { createPortal } from 'react-dom';

export default function ModalPortal({ children }: PropsWithChildren) {
const container = document.getElementById('modal')! as HTMLDivElement;
return createPortal(children, container);
}
23 changes: 23 additions & 0 deletions src/layouts/ModalLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useEffect } from 'react';

type ModalLayoutProps = {
onClose: () => void;
children?: React.ReactNode | undefined;
};

export default function ModalLayout({ onClose, children }: ModalLayoutProps) {
const handleKeyDownClose = (event: KeyboardEvent) => {
if (event.key.toLowerCase() === 'escape') onClose();
};

useEffect(() => {
globalThis.addEventListener('keydown', handleKeyDownClose);
return () => globalThis.removeEventListener('keydown', handleKeyDownClose);
}, []);

return (
<div className="absolute bottom-0 left-0 right-0 top-0 flex items-center justify-center bg-black/50" tabIndex={-1}>
<div className="h-4/5 max-h-375 min-w-375 overflow-auto bg-white p-20">{children}</div>
</div>
);
}
78 changes: 48 additions & 30 deletions src/layouts/page/ProjectLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useMemo } from 'react';
import { useMemo, useState } from 'react';
import { RiSettings5Fill } from 'react-icons/ri';
import { NavLink, Outlet, useParams } from 'react-router-dom';

import ListSidebar from '@components/sidebar/ListSidebar';
import ListProject from '@components/sidebar/ListProject';

import ModalPortal from '@components/common/ModalPortal';
import ModalLayout from '@layouts/ModalLayout';

const dummy = {
teamName: '김찌와 소주',
data: [
Expand All @@ -23,39 +26,54 @@ const dummy = {

export default function ProjectLayout() {
const { projectId } = useParams();
const [showStateModal, setShowStateModal] = useState(false);
const target = useMemo(() => dummy.data.find((d) => d.id === projectId), [projectId]);

return (
<section className="flex h-full p-15">
<ListSidebar label="team" title={dummy.teamName}>
<ListProject data={dummy.data} targetId={projectId} />
</ListSidebar>
<section className="flex w-2/3 flex-col border border-list bg-contents-box">
<header className="flex h-30 items-center justify-between border-b p-10">
<div>
<small className="mr-5 font-bold text-category">project</small>
<span className="text-emphasis">{target?.title}</span>
</div>
<div className="flex cursor-pointer items-center text-sm text-main">
<RiSettings5Fill /> Project Setting
<>
<section className="flex h-full p-15">
<ListSidebar label="team" title={dummy.teamName}>
<ListProject data={dummy.data} targetId={projectId} />
</ListSidebar>
<section className="flex w-2/3 flex-col border border-list bg-contents-box">
<header className="flex h-30 items-center justify-between border-b p-10">
<div>
<small className="mr-5 font-bold text-category">project</small>
<span className="text-emphasis">{target?.title}</span>
</div>
<div className="flex cursor-pointer items-center text-sm text-main">
<RiSettings5Fill /> Project Setting
</div>
</header>
<div className="grow p-10">
<div className="flex justify-between">
<ul className="flex border-b *:mr-15">
<li>
<NavLink to="calendar" className={({ isActive }) => (isActive ? 'text-main' : 'text-emphasis')}>
Calendar
</NavLink>
</li>
<li>
<NavLink to="kanban" className={({ isActive }) => (isActive ? 'text-main' : 'text-emphasis')}>
Kanban
</NavLink>
</li>
</ul>
<div className="text-main">
<button type="button" onClick={() => setShowStateModal(true)}>
<small>+</small> New State
</button>
</div>
</div>
<Outlet />
</div>
</header>
<div className="grow p-10">
<ul className="flex border-b *:mr-15">
<li>
<NavLink to="calendar" className={({ isActive }) => (isActive ? 'text-main' : 'text-emphasis')}>
Calendar
</NavLink>
</li>
<li>
<NavLink to="kanban" className={({ isActive }) => (isActive ? 'text-main' : 'text-emphasis')}>
Kanban
</NavLink>
</li>
</ul>
<Outlet />
</div>
</section>
</section>
</section>
{showStateModal && (
<ModalPortal>
<ModalLayout onClose={() => setShowStateModal(false)} />
</ModalPortal>
)}
</>
);
}

0 comments on commit bf61c55

Please sign in to comment.