-
Notifications
You must be signed in to change notification settings - Fork 5
[FE] feat: 길드 생성 레이아웃 구현 #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
fac42e1
[FE] setting: react-icons 추가 (#31)
zelkovaria 5e08399
[FE] feat: GuildList 기본 버튼 UI 구현 (#31)
zelkovaria 7dfe4e6
[FE] setting: immer 추가 (#31)
zelkovaria 4664d18
[FE] feat: router 설정 (#31)
zelkovaria c7f3683
[FE] feat: modal 관리 및 렌더링 컴포넌트 구현 (#31)
zelkovaria 65ac73e
[FE] feat: 공개/비공개 서버 선택 모달 구현 (#31)
zelkovaria ea7eaf8
[FE] feat: 길드 생성 버튼 클릭시 모달 동작 추가 (#31)
zelkovaria 90ce689
[FE] feat: 모달 상태관리 기능 추가 (#31)
zelkovaria bedc52b
[FE] feat: 메인 Friends 페이지 추가 (#31)
zelkovaria b625246
[FE] feat: Modal 공통 컴포넌트 구현 (#31)
zelkovaria 95e5903
[FE] feat: 이미지 업로드 버튼 UI 구현 (#31)
zelkovaria f44e0bb
[FE] feat: 길드 이름 input ui 구현 (#31)
zelkovaria fd28ac7
[FE] fix: 모달 padding 영역 및 정렬 수정 (#31)
zelkovaria 7056150
[FE] feat: customize 모달 버튼 ui 구현 (#31)
zelkovaria 7e78254
[FE] fix: 모달 정렬 수정 (#31)
zelkovaria e7cf5c5
[FE] feat: 모달 전환 구현 (#31)
zelkovaria 5407061
[FE] fix: 모달 닫힘 오류 수정 (#31)
zelkovaria bf22f6b
[FE] refactor: type 분리 (#31)
zelkovaria e0540df
[FE] fix: modal에서 key를 제거한 구조로 수정 (#31)
zelkovaria 39d39af
[FE] refactor: 길드 생성 버튼 스타일 통합 (#31)
zelkovaria cdd15b9
[FE] refactor: 페이지 화면 비율 수정 (#31)
zelkovaria 3ab65ee
[FE] refactor: CreateGuildModal 폰스 사이즈 수정 (#31)
zelkovaria 883aa54
[FE] refactor: AddServerButton 컴포넌트명 변경 (#31)
zelkovaria 0ea8acd
[FE] refactor: router 구조 및 App.tsx 삭제 (#31)
zelkovaria 48c8092
[FE] fix: modal의 footer margin 조정 (#31)
zelkovaria 24f1b57
[FE] fix: 첫번째 step에서 모달이 닫히지 않는 오류 수정 (#31)
zelkovaria 6e60bab
[FE] refactor: eslint rule 추가 (#31)
zelkovaria 208c6a8
[FE] refactor: Popup의 타입을 modal에서 bottomSheet까지 확장 및 type명 변경 (#31)
zelkovaria 9bc338a
[FE] feat: useFunnel hook 구현 (#31)
zelkovaria 87681ef
[FE] refactor: funnel 구조에 맞춰 guild 생성 모달들의 props를 변경 (#31)
zelkovaria 6bc1edb
[FE] refactor: 길드 생성 모달에 퍼널 구조 적용 (#31)
zelkovaria 012d22f
[FE] refactor: AddGuildButton 컴포넌트 분리 (#31)
zelkovaria 5c90803
[FE] refactor: AddGuildButton 컴포넌트 병합 (#31)
zelkovaria 8f01a77
[FE] refactor: type 및 변수명 수정 (#31)
zelkovaria File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import React from 'react'; | ||
|
|
||
| import useModalStore from '../../../stores/modalStore'; | ||
| import { ModalType } from '../../../types'; | ||
|
|
||
| import * as S from './styles'; | ||
|
|
||
| interface ModalProps { | ||
| children: React.ReactNode; | ||
| name: ModalType; | ||
| } | ||
|
|
||
| const Modal = ({ children, name }: ModalProps) => { | ||
zelkovaria marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const { closeModal, closeAllModal } = useModalStore(); | ||
|
|
||
| return ( | ||
| <> | ||
| <S.Overlay onClick={() => closeModal(name, 'close-modal')} /> | ||
| <S.ModalContainer> | ||
| <S.CloseButton> | ||
| <S.CloseIcon size={28} onClick={() => closeAllModal()} /> | ||
| </S.CloseButton> | ||
| {children} | ||
| </S.ModalContainer> | ||
zelkovaria marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| const Header = ({ children }: { children: React.ReactNode }) => { | ||
| return <S.HeaderWrapper>{children}</S.HeaderWrapper>; | ||
| }; | ||
|
|
||
| const Content = ({ children }: { children: React.ReactNode }) => { | ||
| return <S.ContentWrapper>{children}</S.ContentWrapper>; | ||
| }; | ||
|
|
||
| const Footer = ({ children }: { children: React.ReactNode }) => { | ||
| return <S.FooterWrapper>{children}</S.FooterWrapper>; | ||
| }; | ||
|
|
||
| Modal.Header = Header; | ||
| Modal.Content = Content; | ||
| Modal.Footer = Footer; | ||
zelkovaria marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| export default Modal; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| import { TbX } from 'react-icons/tb'; | ||
| import styled from 'styled-components'; | ||
|
|
||
| export const Overlay = styled.div` | ||
| position: fixed; | ||
| z-index: 1001; | ||
| top: 0; | ||
| left: 0; | ||
|
|
||
| width: 100%; | ||
| height: 100%; | ||
|
|
||
| background-color: rgb(0 0 0 / 50%); | ||
| `; | ||
|
|
||
| export const ModalContainer = styled.div` | ||
| position: fixed; | ||
| z-index: 1002; | ||
| top: 50%; | ||
| left: 50%; | ||
| transform: translate(-50%, -50%); | ||
|
|
||
| display: flex; | ||
| flex-direction: column; | ||
|
|
||
| min-width: 49rem; | ||
| min-height: 36rem; | ||
| border-radius: 0.4rem; | ||
|
|
||
| color: ${({ theme }) => theme.colors.white}; | ||
|
|
||
| background-color: ${({ theme }) => theme.colors.dark[500]}; | ||
|
|
||
| svg { | ||
| color: ${({ theme }) => theme.colors.white}; | ||
| } | ||
| `; | ||
|
|
||
| export const HeaderWrapper = styled.div` | ||
| padding: 0 2.4rem; | ||
| text-align: center; | ||
| `; | ||
|
|
||
| export const ContentWrapper = styled.div` | ||
| margin-top: 0.8rem; | ||
| padding: 0 2.4rem; | ||
| `; | ||
|
|
||
| export const FooterWrapper = styled.div` | ||
| display: flex; | ||
| gap: 1.2rem; | ||
| align-items: center; | ||
| justify-content: center; | ||
|
|
||
| margin-top: 1.6rem; | ||
| `; | ||
|
|
||
| export const CloseButton = styled.div` | ||
| display: flex; | ||
| justify-content: end; | ||
| padding: 2.4rem 2.4rem 0; | ||
| `; | ||
|
|
||
| export const CloseIcon = styled(TbX)` | ||
| cursor: pointer; | ||
| `; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { Fragment, useEffect } from 'react'; | ||
| import { createPortal } from 'react-dom'; | ||
| import { useLocation } from 'react-router-dom'; | ||
|
|
||
| import { useModalStore } from '../../../stores/modalStore'; | ||
|
|
||
| const ModalRenderer = () => { | ||
| const location = useLocation(); | ||
| const { modal, closeAllModal } = useModalStore(); | ||
|
|
||
| useEffect(() => { | ||
| closeAllModal(); | ||
| }, [location.pathname]); | ||
|
|
||
| const portalRoot = document.getElementById('portal-root'); | ||
| if (!portalRoot) return null; | ||
|
|
||
| const renderModals = () => { | ||
| return Object.entries(modal).flatMap(([type, typeModals]) => { | ||
| if (!typeModals) return null; | ||
| return <Fragment key={type}>{typeModals.content}</Fragment>; | ||
| }); | ||
| }; | ||
|
|
||
| return createPortal(<>{renderModals()}</>, portalRoot); | ||
| }; | ||
|
|
||
| export default ModalRenderer; |
27 changes: 27 additions & 0 deletions
27
src/frontend/src/components/guild/CreateGuildModalContent/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import useFunnel from '@/hooks/useFunnel'; | ||
| import CreateGuildModal from '@/pages/FriendsPage/components/CreateGuildModal'; | ||
| import CustomizeGuildModal from '@/pages/FriendsPage/components/CustomizeGuildModal'; | ||
|
|
||
| type CreateGuildSteps = '서버공개여부' | '서버커스텀'; | ||
| const STEP_SEQUENCE: CreateGuildSteps[] = ['서버공개여부', '서버커스텀']; | ||
|
|
||
| const CreateGuildModalContent = () => { | ||
| const { Funnel, moveToNextStep, moveToPrevStep, currentStep } = useFunnel({ | ||
| defaultStep: '서버공개여부', | ||
| stepList: STEP_SEQUENCE, | ||
| }); | ||
|
|
||
| return ( | ||
| <Funnel currentStep={currentStep}> | ||
| <Funnel.Step name="서버공개여부"> | ||
| <CreateGuildModal onNext={moveToNextStep} /> | ||
| </Funnel.Step> | ||
|
|
||
| <Funnel.Step name="서버커스텀"> | ||
| <CustomizeGuildModal onPrev={moveToPrevStep} /> | ||
| </Funnel.Step> | ||
| </Funnel> | ||
| ); | ||
| }; | ||
|
|
||
| export default CreateGuildModalContent; |
zelkovaria marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import useModalStore from '@/stores/modalStore'; | ||
|
|
||
| import CreateGuildModalContent from '../CreateGuildModalContent'; | ||
|
|
||
| import * as S from './styles'; | ||
|
|
||
| const GuildList = () => { | ||
| const { openModal } = useModalStore(); | ||
|
|
||
| const handleChangeModal = () => { | ||
| openModal('basic', <CreateGuildModalContent />); | ||
| }; | ||
|
|
||
| return ( | ||
| <S.GuildList> | ||
| <S.DMButton> | ||
| <S.DiscordIcon size={32} /> | ||
| </S.DMButton> | ||
| {/* 서버 리스트 추가 예정 */} | ||
| <S.AddGuildButton onClick={handleChangeModal}> | ||
| <S.PlusIcon size={24} /> | ||
| </S.AddGuildButton> | ||
| <S.SearchCommunityButton> | ||
| <S.CompassIcon size={36} /> | ||
| </S.SearchCommunityButton> | ||
| </S.GuildList> | ||
| ); | ||
| }; | ||
|
|
||
| export default GuildList; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import { BiCompass } from 'react-icons/bi'; | ||
| import { BsDiscord } from 'react-icons/bs'; | ||
| import { TbPlus } from 'react-icons/tb'; | ||
| import styled from 'styled-components'; | ||
|
|
||
| export const GuildList = styled.nav` | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 2rem; | ||
|
|
||
| width: 8.4rem; | ||
| height: 100%; | ||
| padding: 2.2rem 1rem; | ||
|
|
||
| background-color: ${({ theme }) => theme.colors.dark[800]}; | ||
| `; | ||
|
|
||
| export const DMButton = styled.button` | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
|
|
||
| width: 6.2rem; | ||
| height: 6.2rem; | ||
| border-radius: 1.4rem; | ||
|
|
||
| background-color: ${({ theme }) => theme.colors.blue}; | ||
| `; | ||
|
|
||
| export const DiscordIcon = styled(BsDiscord)` | ||
| color: ${({ theme }) => theme.colors.white}; | ||
| `; | ||
|
|
||
| export const CircleButton = styled.button` | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
|
|
||
| width: 6.25rem; | ||
| height: 6.2rem; | ||
| border-radius: 100%; | ||
|
|
||
| background-color: ${({ theme }) => theme.colors.dark[600]}; | ||
| `; | ||
|
|
||
| export const AddGuildButton = styled(CircleButton)` | ||
| /* 버튼별 역할 구별을 위해 분리 */ | ||
| `; | ||
| export const SearchCommunityButton = styled(CircleButton)` | ||
| /* 버튼별 역할 구별을 위해 분리 */ | ||
| `; | ||
|
|
||
| export const PlusIcon = styled(TbPlus)` | ||
| color: ${({ theme }) => theme.colors.dark[400]}; | ||
| `; | ||
|
|
||
| export const CompassIcon = styled(BiCompass)` | ||
| color: ${({ theme }) => theme.colors.dark[400]}; | ||
| `; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export type CreateGuildStep = 'initial' | 'customize'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { Outlet } from 'react-router-dom'; | ||
|
|
||
| const AuthLayout = () => { | ||
| return ( | ||
| <div> | ||
| <Outlet /> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default AuthLayout; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import React, { useState } from 'react'; | ||
|
|
||
| type UseFunnelProps<T extends string> = { | ||
| defaultStep: T; | ||
| stepList: T[]; | ||
| }; | ||
|
|
||
| type StepProps<T extends string> = { | ||
| children: React.ReactNode; | ||
| name: T; | ||
| }; | ||
|
|
||
| type FunnelProps<T extends string> = { | ||
| currentStep: T; | ||
| children: React.ReactElement<StepProps<T>>[]; | ||
| }; | ||
|
|
||
| const Step = <T extends string>(stepProps: StepProps<T>) => { | ||
| return <>{stepProps.children}</>; | ||
| }; | ||
|
|
||
| const Funnel = <T extends string>({ children, currentStep }: FunnelProps<T>) => { | ||
| const targetStep = children.find((curStep) => curStep.props.name === currentStep); | ||
| if (!targetStep) { | ||
| throw new Error(`${currentStep} 단계에 해당하는 컴포넌트가 존재하지 않습니다.`); | ||
| } | ||
| return <>{targetStep}</>; | ||
| }; | ||
|
|
||
| Funnel.Step = Step; | ||
|
|
||
| const useFunnel = <T extends string>({ defaultStep, stepList }: UseFunnelProps<T>) => { | ||
| const [currentStep, setCurrentStep] = useState(defaultStep); | ||
| const currentIndex = stepList.indexOf(currentStep); | ||
|
|
||
| if (!stepList.includes(defaultStep)) { | ||
| throw new Error('defaultStep은 반드시 stepList에 포함되어 있어야 합니다.'); | ||
| } | ||
|
|
||
| const moveToNextStep = () => { | ||
| const hasNext = currentIndex < stepList.length - 1; | ||
| if (!hasNext) return; | ||
| setCurrentStep(stepList[currentIndex + 1]); | ||
| }; | ||
|
|
||
| const moveToPrevStep = () => { | ||
| const hasPrev = currentIndex > 0; | ||
| if (!hasPrev) return; | ||
| setCurrentStep(stepList[currentIndex - 1]); | ||
| }; | ||
|
|
||
| return { | ||
| Funnel, | ||
| Step, | ||
| currentStep, | ||
| moveToNextStep, | ||
| moveToPrevStep, | ||
| }; | ||
| }; | ||
|
|
||
| export default useFunnel; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.