Skip to content

Commit

Permalink
Merge branch 'develop' into feat/#87
Browse files Browse the repository at this point in the history
  • Loading branch information
selfishAltruism authored Mar 3, 2024
2 parents 0473730 + d593b54 commit 245822a
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 15 deletions.
23 changes: 13 additions & 10 deletions src/components/Atoms/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ButtonUnstyled, buttonUnstyledClasses, ButtonUnstyledProps } from '@mui/base';
import { CircularProgress, styled } from '@mui/material';

const CustomButtonRoot = styled('button')`
Expand All @@ -8,7 +7,7 @@ const CustomButtonRoot = styled('button')`
background-color: #312ed7;
font-size: 18px;
line-height: 21px;
color: ${(props: Props) => props.color || 'white'};
color: ${(props: ButtonProps) => props.color || 'white'};
transition: all 150ms ease;
cursor: pointer;
border: none;
Expand All @@ -17,34 +16,38 @@ const CustomButtonRoot = styled('button')`
opacity: 0.9;
}
&.${buttonUnstyledClasses.active} {
&:active {
opacity: 0.8;
}
&.${buttonUnstyledClasses.focusVisible} {
&:focus-visible {
box-shadow:
0 4px 20px 0 rgba(61, 71, 82, 0.1),
0 0 0 5px rgba(0, 127, 255, 0.5);
outline: none;
}
&.${buttonUnstyledClasses.disabled} {
&:disabled {
opacity: 0.5;
cursor: not-allowed;
background-color: #dadada;
}
`;

interface Props extends ButtonUnstyledProps {
interface ButtonProps {
children?: React.ReactNode;
className?: string;
$loading?: boolean;
disabled?: boolean;
onClick?: (e: React.MouseEvent<HTMLElement>) => void;
color?: string;
type?: 'button' | 'submit' | 'reset' | undefined;
}
export const Button: React.FC<Props> = ({ children, ...props }) => (
<ButtonUnstyled component={CustomButtonRoot} {...props}>

export const Button: React.FC<ButtonProps> = ({ children, ...props }) => (
<CustomButtonRoot {...props}>
{props.$loading ? <CircularProgress size="1.2rem" color="inherit" /> : children}
</ButtonUnstyled>
</CustomButtonRoot>
);

export const NavButton = styled(Button)`
Expand All @@ -70,7 +73,7 @@ const ClearButtonNative = styled('button')`
}
`;

export const ClearButton: React.FC<Props> = ({ children, ...props }) => (
export const ClearButton: React.FC<ButtonProps> = ({ children, ...props }) => (
<ClearButtonNative {...props}>
{props.disabled ? <CircularProgress size="1.2rem" color="inherit" /> : children}
</ClearButtonNative>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ export const ReplyCommentContainer: React.FC<{ model: Model.Comment }> = observe
commentInput.target?.id === model.id ? commentInput.state : InputState.WRITE,
).get();

const handeLongPress = useCallback(model => () => open(model), [open]);
const bind = useLongPress(handeLongPress(model), {
const handleLongPress = useCallback(model => () => open(model), [open]);
const bind = useLongPress(handleLongPress(model), {
cancelOnMovement: true,
captureEvent: true,
onFinish: ev => ev?.preventDefault(),
});

return (
<Li ref={ref} {...bind}>
<Li ref={ref} {...bind()}>
<CommentCardView state={state} model={model} />
</Li>
);
Expand Down
20 changes: 18 additions & 2 deletions src/pages/circle/home/CircleHomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';

import { PageUiStoreImpl } from './CircleHomePageUiStore';
import * as Circle from './components';
Expand All @@ -8,13 +8,29 @@ import { H2 } from './styled';
import { BodyScreen, GNB, Header, PageBody, PageStoreHOC } from '@/components';
import { usePageUiStore } from '@/hooks';

const WEB_WIDTH_CONDITION = 550;
const RESIZE_DELAY = 300;
let timer: string | number | NodeJS.Timeout | undefined;

const CircleHomePage: React.FC = observer(() => {
const { fetch, circles, joinedCircles } = usePageUiStore<PageUiStore.CircleHome>();
const [screenWidth, setScreenWidth] = useState(window.innerWidth);

useEffect(() => {
fetch();
}, [fetch]);

useEffect(() => {
const handleWindowResize = () => {
clearTimeout(timer);
timer = setTimeout(function () {
setScreenWidth(window.innerWidth);
}, RESIZE_DELAY);
};
window.addEventListener('resize', handleWindowResize);
return () => window.removeEventListener('resize', handleWindowResize);
});

return (
<>
<Header title="학부 동아리" />
Expand All @@ -25,7 +41,7 @@ const CircleHomePage: React.FC = observer(() => {
<Circle.ListFrame
items={circles}
emptyText={'아직 등록된 동아리가 없어요!'}
ListComponent={Circle.Slider}
ListComponent={screenWidth > WEB_WIDTH_CONDITION ? Circle.WebSlider : Circle.Slider}
/>
<H2>내 동아리</H2>
<Circle.ListFrame
Expand Down
136 changes: 136 additions & 0 deletions src/pages/circle/home/components/WebSlider/CircleWebSlideCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { memo, useState } from 'react';
import { generatePath, useHistory } from 'react-router';

import { Article } from '@/assets/icons';
import { ClearButton } from '@/components';
import { PAGE_URL } from '@/configs/path';

export const CircleWebSlideCard: React.FC<{ model: Model.Circle }> = memo(
({ model: { id: circleId, mainImage, name, newLineDescription } }) => {
const { push } = useHistory();
const [isFlipped, setFlip] = useState(false);
const handleClick = () => {
if (isFlipped) setFlip(c => !c);
else push(generatePath(PAGE_URL.CircleJoin, { circleId }));
};
const handleFlip = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
setFlip(c => !c);
};

return (
<Card onClick={handleClick}>
<Inner isFlipped={isFlipped}>
<Body>
<Cover mainImage={mainImage} />
<Content>
<ContentName>{name}</ContentName>
<p dangerouslySetInnerHTML={{ __html: newLineDescription }} />
</Content>
</Body>
<Footer>
<Name className="text-ellipsis-line">{name}</Name>
<ClearButton onClick={handleFlip}>
<Icon active={isFlipped} />
</ClearButton>
</Footer>
</Inner>
</Card>
);
},
);

const Card = styled.article`
box-sizing: border-box;
width: 90%;
min-width: 360px;
min-height: 500px;
background: #fff;
border: 1px solid #dadada;
box-shadow: 1px 2px 5px rgb(0 0 0 / 15%);
border-radius: 5px;
overflow: hidden;
text-align: left;
`;

const Body = styled.div`
position: absolute;
width: 100%;
height: calc(100% - 40px);
transition: transform 0.65s;
transform-style: preserve-3d;
> div {
position: absolute;
backface-visibility: hidden;
}
`;

const Cover = styled.div<{ mainImage: string | null }>`
top: 6px;
left: 6px;
width: calc(100% - 12px);
height: calc(100% - 6px);
border-radius: 5px;
${({ mainImage }) =>
mainImage
? css`
background: center / contain no-repeat url(${mainImage});
`
: css`
background: center / contain no-repeat url('/images/empty.png');
background-size: 65%;
`}
background-color: #efefef;
`;

const Name = styled.h3`
margin: 0 35px 0 13px;
line-height: 36px;
font-size: 12px;
font-weight: bold;
backface-visibility: hidden;
`;

const Inner = styled.div<{ isFlipped: boolean }>`
position: relative;
width: 100%;
padding-bottom: 140%; // 5:7 비율
${Body}, ${Name} {
transform: ${({ isFlipped }) => (isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)')};
}
`;

const Content = styled.div`
padding: 13px 9px;
width: 100%;
height: 100%;
background-color: #f8f8f8;
border-radius: 5px;
transform: rotateY(180deg);
overflow: hidden;
`;

const ContentName = styled.div`
margin-bottom: 9px;
line-height: 18px;
font-size: 15px;
font-weight: bold;
`;

const Footer = styled.div`
position: absolute;
bottom: 0;
width: 100%;
height: 40px;
`;

const Icon = styled(Article)`
position: absolute;
top: 9px;
right: 5px;
`;
23 changes: 23 additions & 0 deletions src/pages/circle/home/components/WebSlider/CircleWebSlider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import styled from '@emotion/styled';
import { observer } from 'mobx-react-lite';

import { CircleWebSlideCard } from './CircleWebSlideCard';
import { ListComponent } from '../CircleListFrame';

export const CircleWebSlider: ListComponent = observer(({ items }) => {
return (
<WebScrollWrapper>
{items.map(item => (
<CircleWebSlideCard key={item.id} model={item} />
))}
</WebScrollWrapper>
);
});

const WebScrollWrapper = styled.div`
display: flex;
align-items: center;
gap: 20px;
overflow-x: auto;
padding: 10px 0px;
`;
1 change: 1 addition & 0 deletions src/pages/circle/home/components/WebSlider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CircleWebSlider as WebSlider } from './CircleWebSlider';
1 change: 1 addition & 0 deletions src/pages/circle/home/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './List';
export * from './Slider';
export * from './WebSlider';

export { CircleListFrame as ListFrame } from './CircleListFrame';

0 comments on commit 245822a

Please sign in to comment.