Skip to content

Commit

Permalink
feat: impl /credits
Browse files Browse the repository at this point in the history
  • Loading branch information
malloc3141 committed Oct 14, 2024
1 parent e35a9aa commit 5b4a3fb
Show file tree
Hide file tree
Showing 16 changed files with 472 additions and 26 deletions.
65 changes: 65 additions & 0 deletions packages/web/src/app/credits/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import React from "react";

import styled from "styled-components";

import FlexWrapper from "@sparcs-students/web/common/components/FlexWrapper";
import FoldableSectionTitle from "@sparcs-students/web/common/components/FoldableSectionTitle";
import PageHead from "@sparcs-students/web/common/components/PageHead";

import SectionTitle from "@sparcs-students/web/common/components/SectionTitle";
import MemberCardSection from "@sparcs-students/web/features/credits/components/MemberCardSection";
import credits from "@sparcs-students/web/features/credits/credits";

const CreditCardsFlexWrapper = styled(FlexWrapper)`
gap: 40px;
@media (max-width: ${({ theme }) => theme.responsive.BREAKPOINT.sm}) {
gap: 20px;
}
`;

const ResponsiveMemberCardSectionWrapper = styled.div`
@media (max-width: ${({ theme }) => theme.responsive.BREAKPOINT.sm}) {
margin-left: 16px;
}
`;

const Credits: React.FC = () => {
const [toggleFold, setToggleFold] = React.useState(false);
return (
<FlexWrapper direction="column" gap={60}>
<PageHead title="만든 사람들" />
{credits.map((credit, index) => (
<CreditCardsFlexWrapper
direction="column"
gap={40}
key={credit.semester}
>
{index === 0 ? (
<>
<SectionTitle size="lg">{credit.semester}</SectionTitle>
<ResponsiveMemberCardSectionWrapper>
<MemberCardSection semesterCredit={credit} leftMargin={24} />
</ResponsiveMemberCardSectionWrapper>
</>
) : (
<FoldableSectionTitle
title={credit.semester}
toggle={toggleFold}
toggleHandler={() => {
setToggleFold(!toggleFold);
}}
>
<ResponsiveMemberCardSectionWrapper>
<MemberCardSection semesterCredit={credit} />
</ResponsiveMemberCardSectionWrapper>
</FoldableSectionTitle>
)}
</CreditCardsFlexWrapper>
))}
</FlexWrapper>
);
};
export default Credits;
6 changes: 6 additions & 0 deletions packages/web/src/assets/sparcs-orange.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 14 additions & 4 deletions packages/web/src/common/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
"use client";

import React from "react";
import isPropValid from "@emotion/is-prop-valid";
import styled from "styled-components";

const Card: React.FC<React.PropsWithChildren> = styled.div<{
interface CardProps {
outline?: boolean;
}>`
padding?: string;
gap?: number;
}

const Card = styled.div.withConfig({
shouldForwardProp: prop => isPropValid(prop),
})<CardProps>`
display: flex;
flex-direction: column;
position: relative;
padding: 16px 20px;
align-self: stretch;
padding: ${({ padding }) => padding ?? `32px`};
gap: ${({ gap }) => (gap ? `${gap}px` : "inherit")};
font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: 16px;
line-height: 20px;
font-weight: ${({ theme }) => theme.fonts.WEIGHT.REGULAR};
color: ${({ theme }) => theme.colors.BLACK};
background-color: ${({ theme }) => theme.colors.WHITE};
border-radius: ${({ theme }) => theme.round.md};
Expand Down
22 changes: 22 additions & 0 deletions packages/web/src/common/components/FlexWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import isPropValid from "@emotion/is-prop-valid";
import styled from "styled-components";

interface FlexWrapperProps {
direction: "row" | "column";
gap: number;
justify?: string;
padding?: string;
}

const FlexWrapper = styled.div.withConfig({
shouldForwardProp: prop => isPropValid(prop),
})<FlexWrapperProps>`
display: flex;
position: relative;
flex-direction: ${({ direction }) => direction};
gap: ${({ gap }) => `${gap}px`};
justify-content: ${({ justify }) => justify ?? "flex-start"};
padding: ${({ padding }) => padding ?? 0};
`;

export default FlexWrapper;
63 changes: 46 additions & 17 deletions packages/web/src/common/components/FoldableSectionTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,67 @@
"use client";

import React from "react";

import isPropValid from "@emotion/is-prop-valid";
import styled from "styled-components";

import TextButton from "@sparcs-students/web/common/components/Buttons/TextButton";
import SectionTitle from "@sparcs-students/web/common/components/SectionTitle";
import Icon from "@sparcs-students/web/common/components/Icon";

const FoldableSectionOuter = styled.div`
width: 100%;
max-width: calc(100vw + (100% - 100vw));
`;

const FoldableSectionTitleInner = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
width: 100%;
`;

export const MoreInfo = styled.div`
font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: 14px;
line-height: 20px;
font-weight: ${({ theme }) => theme.fonts.WEIGHT.REGULAR};
color: ${({ theme }) => theme.colors.BLACK};
text-decoration-line: underline;
cursor: pointer;
const ChildrenOuter = styled.div.withConfig({
shouldForwardProp: prop => isPropValid(prop),
})<{ margin?: string }>`
margin-top: ${({ margin }) => margin};
margin-left: 24px;
`;

const FoldableSectionTitle: React.FC<{
iconType?: string;
title: string;
toggle: boolean;
toggleHandler: () => void;
}> = ({ title, toggle, toggleHandler }) => (
<FoldableSectionTitleInner>
<SectionTitle size="lg">{title}</SectionTitle>
<MoreInfo onClick={toggleHandler}>{toggle ? `접기` : `펼치기`}</MoreInfo>
</FoldableSectionTitleInner>
);
toggle?: boolean;
toggleHandler?: () => void;
children?: React.ReactNode;
childrenMargin?: string;
}> = ({
iconType = null,
title,
toggle = null,
toggleHandler = null,
children = null,
childrenMargin = "40px",
}) => {
const [open, setOpen] = React.useState<boolean>(true);
const openHandler = () => setOpen(!open);

return (
<FoldableSectionOuter>
<FoldableSectionTitleInner>
{iconType && <Icon type={iconType} size={16} color="white" />}
<SectionTitle size="lg">{title}</SectionTitle>
<TextButton
text={toggle ?? open ? `접기` : `펼치기`}
onClick={toggleHandler ?? openHandler}
/>
</FoldableSectionTitleInner>
{(toggle ?? open) && children && (
<ChildrenOuter margin={childrenMargin}>{children}</ChildrenOuter>
)}
</FoldableSectionOuter>
);
};

export default FoldableSectionTitle;
25 changes: 25 additions & 0 deletions packages/web/src/common/components/PageHead/_atomic/PageTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";

import React from "react";

import styled from "styled-components";

const PageTitleInner = styled.div`
position: relative;
width: fit-content;
font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: 30px;
line-height: 24px;
@media (max-width: ${({ theme }) => theme.responsive.BREAKPOINT.sm}) {
font-size: 24px;
line-height: 36px;
}
font-weight: ${({ theme }) => theme.fonts.WEIGHT.SEMIBOLD};
color: ${({ theme }) => theme.colors.BLACK};
`;

const PageTitle: React.FC<React.PropsWithChildren> = ({
children = <div />,
}) => <PageTitleInner>{children}</PageTitleInner>;

export default PageTitle;
53 changes: 53 additions & 0 deletions packages/web/src/common/components/PageHead/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";

import styled from "styled-components";

import PageTitle from "./_atomic/PageTitle";

// 주석 처리된 부분은 BreadCrumb 컴포넌트를 쓰게 된다면 다시 추가
interface PageHeadProps {
// items: { name: string; path: string }[];
title: string;
// enableLast?: boolean;
action?: React.ReactNode;
}

const PageHeadWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 20px;
@media (max-width: ${({ theme }) => theme.responsive.BREAKPOINT.sm}) {
gap: 12px;
}
align-items: flex-start;
align-self: stretch;
`;

const TitleWrapper = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
@media (max-width: ${({ theme }) => theme.responsive.BREAKPOINT.sm}) {
flex-direction: column;
align-items: flex-start;
gap: 20px;
}
`;

const PageHead: React.FC<PageHeadProps> = ({
// items,
title,
// enableLast = false,
action = null,
}) => (
<PageHeadWrapper>
{/* <BreadCrumb items={items} enableLast={enableLast} /> */}
<TitleWrapper>
<PageTitle>{title}</PageTitle>
{action && <div>{action}</div>}
</TitleWrapper>
</PageHeadWrapper>
);

export default PageHead;
5 changes: 3 additions & 2 deletions packages/web/src/common/components/SectionTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ const IdentityBar = styled.div`

const Title = styled.p<{ size: Size }>`
font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: ${({ size }) => (size === "sm" ? "20px" : "24px")};
line-height: ${({ size }) => (size === "sm" ? "28px" : "32px")};
font-size: ${({ size }) =>
size === "sm" ? "20px" : "20px"}; // TODO: 반응형 사이즈 재확인
line-height: ${({ size }) => (size === "sm" ? "24px" : "24px")};
font-weight: ${({ theme }) => theme.fonts.WEIGHT.MEDIUM};
color: ${({ theme }) => theme.colors.BLACK};
`;
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/constants/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const paths = {
},
],
},
MADE_BY: { name: "만든 사람들", path: "/" },
MADE_BY: { name: "만든 사람들", path: "/credits" },
LICENSE: { name: "라이센스", path: "/" },
TERMS_OF_SERVICE: { name: "이용 약관", path: "/" },
LOGIN: { name: "로그인", path: "/login" },
Expand Down
70 changes: 70 additions & 0 deletions packages/web/src/features/credits/components/MemberCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useState } from "react";

import Image from "next/image";
import styled from "styled-components";

import SparcsLogo from "@sparcs-students/web/assets/sparcs-orange.svg";
import Card from "@sparcs-students/web/common/components/Card";
import Typography from "@sparcs-students/web/common/components/Typography";

import type { Member } from "../credits";

const MemberWrapper = styled.div`
display: flex;
flex-direction: row;
align-items: flex-end;
gap: 6px;
`;

const MemberCard = ({ member }: { member: Member }) => {
const [displayText, setDisplayText] = useState(member.role);

const handleMouseEnter = () => {
if (member.comment) {
setDisplayText(member.comment);
}
};

const handleMouseLeave = () => {
setDisplayText(member.role);
};

return (
<Card padding="10px 15px 15px 15px" gap={5}>
<MemberWrapper>
<Image src={SparcsLogo} alt="SPARCS Logo" height={20} />
<Typography
ff="RALEWAY"
fw="EXTRABOLD"
fs={14}
lh={20}
color="SPARCS.main"
>
{member.nickname}
</Typography>
<Typography
ff="NANUM_SQUARE"
fw="EXTRABOLD" // TODO: 현재 NANUM_SQUARE는 EXTRABOLD만 존재함
fs={10}
lh={16}
color="SPARCS.member"
>
{member.name}
</Typography>
</MemberWrapper>
<Typography
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
ff="RALEWAY"
fw="EXTRABOLD"
fs={10}
lh={20}
color="GRAY.900"
>
{displayText}
</Typography>
</Card>
);
};

export default MemberCard;
Loading

0 comments on commit 5b4a3fb

Please sign in to comment.