Skip to content

Commit

Permalink
feat: 꿀조합 상세 페이지 디자인 마이그레이션 (#71)
Browse files Browse the repository at this point in the history
* feat: 박스 svg icon 추가

* style: PageHeader import문 추가

* feat: RecipeFavoriteButton 컴포넌트 디자인 수정

* feat: 꿀조합 상세 페이지 디자인 수정

* feat: 댓글 리스트 스타일 마이그레이션

* feat: 댓글작성폼 스타일 마이그레이션

* fix: className 수정

* feat: 꿀조합 상세 페이지 title 스타일 수정

* feat: line height global style로 적용

* feat: plane 아이콘 교체

* style: 린트 적용

* feat: 댓글창 스타일 마이그레이션

* feat: section title 컴포넌트 디자인 마이그레이션

* feat: 꿀조합 상세페이지 Text 컴포넌트와 SectionTitle 컴포넌트로 교체

* feat: RecipeDetail 타입 변경

* feat: 사용한 상품 바텀시트 적용

* fix: 사진을 사용자의 프로필 사진으로 교체

* refactor: CommentItem의 텍스트를 Text 컴포넌트로 교체

* feat: borderRadius 삭제

* feat: svg icon 하나로 교체

* feat: favoriteButton 스타일 수정

* style: 린트 적용

* feat: 댓글 form 스타일 수정

* feat: 꿀조합 상세 디자인 변경 적용

* fix: rate->averageRating으로 이름 변경

* refactor: ProductOverviewItem -> ProductOVerviewList 컴포넌트로 교체

* feat: CommentList, CommentItem 스토리북 추가
  • Loading branch information
xodms0309 authored Apr 14, 2024
1 parent ae36aa8 commit a56add6
Show file tree
Hide file tree
Showing 26 changed files with 482 additions and 290 deletions.
17 changes: 13 additions & 4 deletions .storybook/preview-body.html
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,19 @@
d="M14.485 9.47a.75.75 0 0 0-1.063 1.06c1.164 1.168 1.133 3.279-.303 4.72l-4.847 4.866c-1.435 1.44-3.533 1.47-4.694.304c-1.164-1.168-1.132-3.28.303-4.72l2.424-2.433a.75.75 0 0 0-1.063-1.059l-2.424 2.433c-1.911 1.92-2.151 4.982-.303 6.838c1.85 1.858 4.907 1.615 6.82-.304l4.847-4.867c1.911-1.918 2.151-4.982.303-6.837Z"
></path>
</g>
<symbol id="plane" width="32" height="32" viewBox="0 0 256 256">
<path
d="M232 127.89a16 16 0 0 1-8.18 14L55.91 237.9A16.14 16.14 0 0 1 48 240a16 16 0 0 1-15.05-21.34l27.35-79.95a4 4 0 0 1 3.79-2.71H136a8 8 0 0 0 8-8.53a8.19 8.19 0 0 0-8.26-7.47H64.16a4 4 0 0 1-3.79-2.7l-27.44-80a16 16 0 0 1 22.92-19.23l168 95.89a16 16 0 0 1 8.15 13.93Z"
/>
<symbol id="plane" viewBox="0 0 18 19">
<g clip-path="url(#clip0_4423_13410)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M15.1975 0.625674C15.5681 0.490352 15.9695 0.4631 16.3553 0.547225C16.7447 0.632193 17.1016 0.827207 17.3834 1.10908C17.6653 1.39096 17.8603 1.74785 17.9453 2.13732C18.0294 2.52293 18.0021 2.92444 17.8669 3.29502L13.2717 17.0676C13.1597 17.4063 12.9624 17.7115 12.6989 17.9522C12.4363 18.1922 12.1165 18.3608 11.7702 18.442C11.4238 18.5265 11.0613 18.5193 10.7185 18.4213C10.3759 18.3235 10.0647 18.1383 9.81533 17.884L7.35018 15.4301L4.76068 16.7692C4.55875 16.8736 4.31669 16.8636 4.12405 16.7428C3.93143 16.6222 3.81686 16.4087 3.82276 16.1815L3.92892 12.0881L12.9867 5.50856C13.3458 5.24774 13.4255 4.74521 13.1646 4.38615C12.9038 4.02708 12.4013 3.94744 12.0422 4.20826L2.83074 10.8994L0.606834 8.67548C0.365991 8.4348 0.188451 8.13786 0.0906127 7.81172C-0.00653 7.48791 -0.0223126 7.14519 0.0446081 6.81389C0.111615 6.45195 0.273411 6.11419 0.513558 5.8351C0.75535 5.5541 1.0678 5.34276 1.4186 5.22295L1.42294 5.22147L15.1975 0.625674Z"
/>
</g>
<defs>
<clipPath id="clip0_4423_13410">
<rect width="18" height="18" fill="white" transform="translate(0 0.5)" />
</clipPath>
</defs>
</symbol>
<symbol id="info" viewBox="0 0 16 16">
<path
Expand Down
3 changes: 2 additions & 1 deletion src/components/Common/SectionTitle/SectionTitle.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ export const Default: Story = {
},
};

export const Bookmarked: Story = {
export const HasSearch: Story = {
args: {
name: '사이다',
hasSearchLink: true,
},
};
66 changes: 23 additions & 43 deletions src/components/Common/SectionTitle/SectionTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,34 @@
import { Button, Heading, Link, theme } from '@fun-eat/design-system';
import { Link as RouterLink } from 'react-router-dom';
import styled from 'styled-components';
import { Link } from 'react-router-dom';

import { SvgIcon } from '@/components/Common';
import { useRoutePage } from '@/hooks/common';
import { container, wrapper } from './sectionTitle.css';

import { SvgIcon, Text } from '@/components/Common';
import { PATH } from '@/constants/path';
import { vars } from '@/styles/theme.css';

interface SectionTitleProps {
name: string;
link?: string;
hasSearchLink?: boolean;
}

const SectionTitle = ({ name, link }: SectionTitleProps) => {
const { routeBack } = useRoutePage();

const SectionTitle = ({ name, hasSearchLink }: SectionTitleProps) => {
return (
<SectionTitleContainer>
<SectionTitleWrapper>
<Button type="button" variant="transparent" onClick={routeBack} aria-label="뒤로 가기">
<SvgIcon variant="arrow" fill={theme.colors.gray5} width={15} height={15} />
</Button>
{link ? (
<Link as={RouterLink} to={link} block>
<ProductName size="xl">{name}</ProductName>
</Link>
) : (
<ProductName size="xl">{name}</ProductName>
)}
{link && <SvgIcon variant="link" width={20} height={20} />}
</SectionTitleWrapper>
</SectionTitleContainer>
<div className={container}>
<div className={wrapper}>
<Link to=".." relative="path">
<SvgIcon variant="arrowLeft" stroke={vars.colors.black} height={24} />
</Link>
<Text size="headline" weight="semiBold">
{name}
</Text>
</div>
{hasSearchLink && (
<Link to={PATH.SEARCH}>
<SvgIcon variant="search2" stroke={vars.colors.black} width={20} height={20} />
</Link>
)}
</div>
);
};

export default SectionTitle;

const SectionTitleContainer = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`;

const SectionTitleWrapper = styled.div`
display: flex;
align-items: center;
svg {
padding-top: 2px;
}
`;

const ProductName = styled(Heading)`
margin: 0 5px 0 16px;
`;
13 changes: 13 additions & 0 deletions src/components/Common/SectionTitle/sectionTitle.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { style } from '@vanilla-extract/css';

export const container = style({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
});

export const wrapper = style({
display: 'flex',
gap: 18,
alignItems: 'flex-start',
});
1 change: 1 addition & 0 deletions src/components/Common/Svg/SvgIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const SVG_ICON_VARIANTS = [
'arrowUpDown',
'heartEmpty',
'heartFilled',
'box',
'close2',
'disk',
] as const;
Expand Down
15 changes: 13 additions & 2 deletions src/components/Common/Svg/SvgSprite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,19 @@ const SvgSprite = () => {
<path d="M14.485 9.47a.75.75 0 0 0-1.063 1.06c1.164 1.168 1.133 3.279-.303 4.72l-4.847 4.866c-1.435 1.44-3.533 1.47-4.694.304c-1.164-1.168-1.132-3.28.303-4.72l2.424-2.433a.75.75 0 0 0-1.063-1.059l-2.424 2.433c-1.911 1.92-2.151 4.982-.303 6.838c1.85 1.858 4.907 1.615 6.82-.304l4.847-4.867c1.911-1.918 2.151-4.982.303-6.837Z" />
</g>
</symbol>
<symbol id="plane" viewBox="0 0 256 256">
<path d="M232 127.89a16 16 0 0 1-8.18 14L55.91 237.9A16.14 16.14 0 0 1 48 240a16 16 0 0 1-15.05-21.34l27.35-79.95a4 4 0 0 1 3.79-2.71H136a8 8 0 0 0 8-8.53a8.19 8.19 0 0 0-8.26-7.47H64.16a4 4 0 0 1-3.79-2.7l-27.44-80a16 16 0 0 1 22.92-19.23l168 95.89a16 16 0 0 1 8.15 13.93Z" />
<symbol id="plane" viewBox="0 0 18 19">
<g clipPath="url(#clip0_4423_13410)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.1975 0.625674C15.5681 0.490352 15.9695 0.4631 16.3553 0.547225C16.7447 0.632193 17.1016 0.827207 17.3834 1.10908C17.6653 1.39096 17.8603 1.74785 17.9453 2.13732C18.0294 2.52293 18.0021 2.92444 17.8669 3.29502L13.2717 17.0676C13.1597 17.4063 12.9624 17.7115 12.6989 17.9522C12.4363 18.1922 12.1165 18.3608 11.7702 18.442C11.4238 18.5265 11.0613 18.5193 10.7185 18.4213C10.3759 18.3235 10.0647 18.1383 9.81533 17.884L7.35018 15.4301L4.76068 16.7692C4.55875 16.8736 4.31669 16.8636 4.12405 16.7428C3.93143 16.6222 3.81686 16.4087 3.82276 16.1815L3.92892 12.0881L12.9867 5.50856C13.3458 5.24774 13.4255 4.74521 13.1646 4.38615C12.9038 4.02708 12.4013 3.94744 12.0422 4.20826L2.83074 10.8994L0.606834 8.67548C0.365991 8.4348 0.188451 8.13786 0.0906127 7.81172C-0.00653 7.48791 -0.0223126 7.14519 0.0446081 6.81389C0.111615 6.45195 0.273411 6.11419 0.513558 5.8351C0.75535 5.5541 1.0678 5.34276 1.4186 5.22295L1.42294 5.22147L15.1975 0.625674Z"
/>
</g>
<defs>
<clipPath id="clip0_4423_13410">
<rect width="18" height="18" fill="white" transform="translate(0 0.5)" />
</clipPath>
</defs>
</symbol>
<symbol id="info" viewBox="0 0 16 16">
<path d="M8 7a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-1 0v-3A.5.5 0 0 1 8 7zm0-.75a.749.749 0 1 0 0-1.5.749.749 0 0 0 0 1.498zM2 8a6 6 0 1 1 12 0A6 6 0 0 1 2 8zm6-5a5 5 0 1 0 0 10A5 5 0 0 0 8 3z" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import type { Product } from '@/types/product';

interface ProductOverviewListProps {
products: Product[];
isSearchPage?: boolean;
hasBorder?: boolean;
}

const ProductOverviewList = ({ products, isSearchPage = false }: ProductOverviewListProps) => {
const ProductOverviewList = ({ products, hasBorder = false }: ProductOverviewListProps) => {
return (
<ul className={container}>
{products.map(({ id, image, name, price, averageRating }) => (
<li key={id}>
<Link to={`${PATH.PRODUCT_LIST}/detail/${id}`}>
<ProductOverviewItem image={image} name={name} price={price} rate={averageRating} />
</Link>
{isSearchPage && (
{hasBorder && (
<>
<div style={{ height: '20px' }} />
<hr style={{ border: '0.5px solid #e6e6e6' }} />
Expand Down
102 changes: 51 additions & 51 deletions src/components/Recipe/CommentForm/CommentForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Button, Spacing, Text, Textarea, useTheme, useToastActionContext } from '@fun-eat/design-system';
import { useToastActionContext } from '@fun-eat/design-system';
import type { ChangeEventHandler, FormEventHandler, RefObject } from 'react';
import { useState } from 'react';
import styled from 'styled-components';
import { useRef, useState } from 'react';

import { SvgIcon } from '@/components/Common';
import { commentForm, commentTextarea, container, profileImage, sendButton } from './commentForm.css';

import { SvgIcon, Text } from '@/components/Common';
import { useScroll } from '@/hooks/common';
import { useMemberQuery } from '@/hooks/queries/members';
import { useRecipeCommentMutation } from '@/hooks/queries/recipe';
import { vars } from '@/styles/theme.css';

interface CommentFormProps {
recipeId: number;
Expand All @@ -15,16 +18,27 @@ interface CommentFormProps {
const MAX_COMMENT_LENGTH = 200;

const CommentForm = ({ recipeId, scrollTargetRef }: CommentFormProps) => {
const { data: member } = useMemberQuery();

const [commentValue, setCommentValue] = useState('');
const { mutate } = useRecipeCommentMutation(recipeId);

const theme = useTheme();
const { toast } = useToastActionContext();

const { scrollToPosition } = useScroll();

const textAreaRef = useRef<HTMLTextAreaElement>(null);

const autoResizeTextarea = () => {
if (textAreaRef.current) {
textAreaRef.current.style.height = 'auto';
textAreaRef.current.style.height = textAreaRef.current.scrollHeight + 'px';
}
};

const handleCommentInput: ChangeEventHandler<HTMLTextAreaElement> = (e) => {
setCommentValue(e.target.value);
autoResizeTextarea();
};

const handleSubmitComment: FormEventHandler<HTMLFormElement> = (e) => {
Expand All @@ -51,54 +65,40 @@ const CommentForm = ({ recipeId, scrollTargetRef }: CommentFormProps) => {
};

return (
<CommentFormContainer>
<Form onSubmit={handleSubmitComment}>
<CommentTextarea
placeholder="댓글을 입력하세요. (200자)"
value={commentValue}
onChange={handleCommentInput}
maxLength={MAX_COMMENT_LENGTH}
/>
<SubmitButton variant="transparent" disabled={commentValue.length === 0}>
<SvgIcon
variant="plane"
width={30}
height={30}
fill={commentValue.length === 0 ? theme.colors.gray2 : theme.colors.gray4}
<div className={container}>
<img
className={profileImage}
src={member?.profileImage}
width={29}
height={29}
alt={`${member?.nickname}의 프로필 사진`}
/>
<>
<form className={commentForm} onSubmit={handleSubmitComment}>
<textarea
className={commentTextarea}
placeholder="댓글을 남겨보세요! (200자)"
value={commentValue}
onChange={handleCommentInput}
maxLength={MAX_COMMENT_LENGTH}
rows={1}
ref={textAreaRef}
/>
</SubmitButton>
</Form>
<Spacing size={8} />
<Text size="xs" color={theme.textColors.info} align="right">
{commentValue.length}자 / {MAX_COMMENT_LENGTH}
</Text>
</CommentFormContainer>
<Text size="caption4" color="disabled">
{commentValue.length}/200
</Text>
<button className={sendButton}>
<SvgIcon
variant="plane"
width={18}
height={18}
fill={commentValue.length === 0 ? vars.colors.gray3 : vars.colors.gray5}
/>
</button>
</form>
</>
</div>
);
};

export default CommentForm;

const CommentFormContainer = styled.div`
position: fixed;
bottom: 0;
width: calc(100% - 40px);
max-width: 540px;
padding: 16px 0;
background: ${({ theme }) => theme.backgroundColors.default};
`;

const Form = styled.form`
display: flex;
gap: 4px;
justify-content: space-around;
align-items: center;
`;

const CommentTextarea = styled(Textarea)`
height: 50px;
padding: 8px;
`;

const SubmitButton = styled(Button)`
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
`;
43 changes: 43 additions & 0 deletions src/components/Recipe/CommentForm/commentForm.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { vars } from '@/styles/theme.css';
import { style } from '@vanilla-extract/css';

export const container = style({
display: 'flex',
gap: 8,
alignItems: 'flex-end',
marginBottom: 24,
});

export const commentForm = style({
display: 'flex',
gap: 8,
alignItems: 'flex-end',
width: '100%',
padding: '6px 16px 9px 16px',
background: vars.colors.background.category,
borderRadius: 20,
});

export const commentTextarea = style({
width: '100%',
height: '100%',
border: 'none',
outline: 'none',
background: 'none',
fontSize: '1.4rem',
resize: 'none',

selectors: {
'&:placeholder': {
color: '#808080',
},
},
});

export const profileImage = style({
borderRadius: '50%',
});

export const sendButton = style({
display: 'inherit',
});
18 changes: 18 additions & 0 deletions src/components/Recipe/CommentItem/CommentItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Meta, StoryObj } from '@storybook/react';

import CommentItem from './CommentItem';

import comments from '@/mocks/data/comments.json';

const meta: Meta<typeof CommentItem> = {
title: 'recipe/CommentItem',
component: CommentItem,
args: {
recipeComment: comments.comments[0],
},
};

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};
Loading

0 comments on commit a56add6

Please sign in to comment.