-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 레이아웃 기본 구성 * feat: 모바일 대응 추가 * feat: 쿼리 파라미터 일반화 추가 * refactor: DOM에 키가 들어가지 않도록 수정 * chore: 주석 추가
- Loading branch information
Showing
13 changed files
with
323 additions
and
27 deletions.
There are no files selected for viewing
This file contains 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 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
60 changes: 60 additions & 0 deletions
60
src/components/community/layout/DesktopCommunityLayout.tsx
This file contains 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,60 @@ | ||
import styled from '@emotion/styled'; | ||
import { m } from 'framer-motion'; | ||
import { FC, ReactNode } from 'react'; | ||
|
||
import { layoutCSSVariable } from '@/components/layout/utils'; | ||
|
||
interface DesktopCommunityLayoutProps { | ||
isDetailOpen: boolean; | ||
listSlot: ReactNode; | ||
detailSlot: ReactNode; | ||
} | ||
|
||
const DETAIL_SLOT_WIDTH = 560; | ||
|
||
const DesktopCommunityLayout: FC<DesktopCommunityLayoutProps> = ({ isDetailOpen, listSlot, detailSlot }) => { | ||
return ( | ||
<Container> | ||
<ListSlot>{listSlot}</ListSlot> | ||
<DetailSlot | ||
initial={{ width: 0 }} | ||
animate={{ width: isDetailOpen ? DETAIL_SLOT_WIDTH : 0 }} | ||
transition={{ bounce: 0 }} | ||
> | ||
<DetailSlotInner>{detailSlot}</DetailSlotInner> | ||
</DetailSlot> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default DesktopCommunityLayout; | ||
|
||
const Container = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
width: 100%; | ||
height: ${layoutCSSVariable.contentAreaHeight}; | ||
`; | ||
|
||
const ListSlot = styled.div` | ||
flex: 1 1 0; | ||
max-width: 560px; | ||
height: 100%; | ||
`; | ||
|
||
const DetailSlot = styled(m.div)` | ||
position: relative; | ||
width: 100%; | ||
max-width: 560px; | ||
height: 100%; | ||
overflow: hidden; | ||
`; | ||
|
||
const DetailSlotInner = styled.div` | ||
position: absolute; | ||
top: 0; | ||
right: 0; | ||
bottom: 0; | ||
width: 560px; | ||
min-width: ${DETAIL_SLOT_WIDTH}px; | ||
`; |
This file contains 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,42 @@ | ||
import styled from '@emotion/styled'; | ||
import { colors } from '@sopt-makers/colors'; | ||
import { m } from 'framer-motion'; | ||
import { FC, ReactNode } from 'react'; | ||
|
||
import { layoutCSSVariable } from '@/components/layout/utils'; | ||
|
||
interface MobileCommunityLayoutProps { | ||
isDetailOpen: boolean; | ||
listSlot: ReactNode; | ||
detailSlot: ReactNode; | ||
} | ||
|
||
const MobileCommunityLayout: FC<MobileCommunityLayoutProps> = ({ isDetailOpen, listSlot, detailSlot }) => { | ||
return ( | ||
<Container> | ||
<ListSlotBox>{listSlot}</ListSlotBox> | ||
<DetailSlotBox initial={{ x: '100%' }} animate={{ x: isDetailOpen ? '0%' : '100%' }} transition={{ bounce: 0 }}> | ||
{detailSlot} | ||
</DetailSlotBox> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default MobileCommunityLayout; | ||
|
||
const Container = styled.div` | ||
position: relative; | ||
height: ${layoutCSSVariable.contentAreaHeight}; | ||
overflow: hidden; | ||
`; | ||
|
||
const ListSlotBox = styled.div` | ||
position: absolute; | ||
inset: 0; | ||
`; | ||
|
||
const DetailSlotBox = styled(m.div)` | ||
position: absolute; | ||
inset: 0; | ||
background-color: ${colors.background}; | ||
`; |
This file contains 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,43 @@ | ||
import { colors } from '@sopt-makers/colors'; | ||
import { FC } from 'react'; | ||
|
||
import Responsive from '@/components/common/Responsive'; | ||
import DesktopCommunityLayout from '@/components/community/layout/DesktopCommunityLayout'; | ||
import MobileCommunityLayout from '@/components/community/layout/MobileCommunityLayout'; | ||
import { FeedDetailLink, TagLink, useFeedDetailParam, useTagParam } from '@/components/community/queryParam'; | ||
|
||
const CommunityPage: FC = () => { | ||
const [feed] = useFeedDetailParam(); | ||
const [tag] = useTagParam(); | ||
|
||
const feedList = ( | ||
<div style={{ backgroundColor: colors.blue600, display: 'flex', flexDirection: 'column' }}> | ||
<TagLink tagId='tag1'>태그1</TagLink> | ||
<TagLink tagId='tag2'>태그2</TagLink> | ||
<TagLink tagId='tag3'>태그3</TagLink> | ||
<div>CurrentTag: {tag}</div> | ||
<FeedDetailLink feedId='ramen'>한강라면</FeedDetailLink> | ||
<FeedDetailLink feedId='chicken'>치킨</FeedDetailLink> | ||
</div> | ||
); | ||
|
||
const feedDetail = ( | ||
<div style={{ backgroundColor: colors.green600 }}> | ||
<FeedDetailLink feedId={undefined}>닫기</FeedDetailLink> | ||
<div>피드 ID: {feed}</div> | ||
</div> | ||
); | ||
|
||
return ( | ||
<> | ||
<Responsive only='desktop'> | ||
<DesktopCommunityLayout isDetailOpen={feed !== ''} listSlot={feedList} detailSlot={feedDetail} /> | ||
</Responsive> | ||
<Responsive only='mobile'> | ||
<MobileCommunityLayout isDetailOpen={feed !== ''} listSlot={feedList} detailSlot={feedDetail} /> | ||
</Responsive> | ||
</> | ||
); | ||
}; | ||
|
||
export default CommunityPage; |
This file contains 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,51 @@ | ||
import Link from 'next/link'; | ||
import { useRouter } from 'next/router'; | ||
import { ComponentPropsWithoutRef, forwardRef } from 'react'; | ||
import { StringParam, useQueryParam, withDefault } from 'use-query-params'; | ||
|
||
/** | ||
* 쿼리 파라미터와 연동된 상태를 쉽게 만들 수 있게 해줍니다. paramKey가 쿼리 파라미터의 키가 됩니다. | ||
*/ | ||
function createLinkComponent<T extends string>({ paramKey }: { paramKey: T }) { | ||
type Key = { | ||
[K in `${T}Id`]: string | undefined; | ||
}; | ||
|
||
const ParamLink = forwardRef< | ||
HTMLAnchorElement, | ||
Omit<ComponentPropsWithoutRef<typeof Link>, 'href' | 'shallow'> & Key | ||
>((props, ref) => { | ||
const { pathname, query } = useRouter(); | ||
const value = props[`${paramKey}Id`] as string | undefined; | ||
|
||
const newProps = { ...props }; | ||
delete newProps[`${paramKey}Id`]; | ||
|
||
return ( | ||
<Link | ||
ref={ref} | ||
{...newProps} | ||
href={{ | ||
pathname, | ||
query: { | ||
...query, | ||
[paramKey]: value, | ||
}, | ||
}} | ||
shallow | ||
/> | ||
); | ||
}); | ||
|
||
const useParam = () => { | ||
return useQueryParam(paramKey, withDefault(StringParam, undefined)); | ||
}; | ||
|
||
return [ParamLink, useParam] as const; | ||
} | ||
|
||
export const [TagLink, useTagParam] = createLinkComponent({ paramKey: 'tag' }); | ||
|
||
export const [CategoryLink, useCategoryParam] = createLinkComponent({ paramKey: 'category' }); | ||
|
||
export const [FeedDetailLink, useFeedDetailParam] = createLinkComponent({ paramKey: 'feed' }); |
This file contains 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 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 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 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,22 @@ | ||
interface CreateLayoutCSSVariableOptions { | ||
headerHeight: number; | ||
footerHeight?: number; | ||
} | ||
|
||
const layoutCSSVariableNames = { | ||
globalHeaderHeight: '--global-header-height', | ||
globalFooterHeight: '--global-footer-height', | ||
contentAreaHeight: '--content-area-height', | ||
}; | ||
|
||
export const layoutCSSVariable = Object.fromEntries( | ||
Object.entries(layoutCSSVariableNames).map(([key, value]) => [key, `var(${value})`]), | ||
) as Record<keyof typeof layoutCSSVariableNames, string>; | ||
|
||
export function createLayoutCSSVariable({ headerHeight, footerHeight = 0 }: CreateLayoutCSSVariableOptions) { | ||
return ` | ||
${layoutCSSVariableNames.globalHeaderHeight}: ${headerHeight}px; | ||
${layoutCSSVariableNames.globalFooterHeight}: ${footerHeight}px; | ||
${layoutCSSVariableNames.contentAreaHeight}: calc(100vh - var(--global-header-height) - var(--global-footer-height)); | ||
`; | ||
} |
This file contains 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
Oops, something went wrong.