diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index f7e86e8f..1dd32072 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -4,3 +4,9 @@ crossorigin="anonymous" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.6/dist/web/static/pretendard-dynamic-subset.css" /> + diff --git a/apps/duri/src/App.tsx b/apps/duri/src/App.tsx index 3e8c4753..90ca87f8 100644 --- a/apps/duri/src/App.tsx +++ b/apps/duri/src/App.tsx @@ -19,6 +19,10 @@ import Shop from '@pages/Shop'; import Portfolio from '@pages/Shop/Portfolio'; import ShopDetail from '@pages/Shop/ShopDetail'; +import 'react-spring-bottom-sheet/dist/style.css'; + +import PortfolioDetail from './pages/Shop/PortfolioDetail'; + function App() { return ( @@ -34,18 +38,24 @@ function App() { } /> } /> } /> - + } /> } /> } /> - + } /> + } + /> } /> - } /> - - } /> + } + /> + } /> ); diff --git a/apps/duri/src/components/shop/DesignerInfo.tsx b/apps/duri/src/components/shop/DesignerInfo.tsx index cb574226..6ee0b971 100644 --- a/apps/duri/src/components/shop/DesignerInfo.tsx +++ b/apps/duri/src/components/shop/DesignerInfo.tsx @@ -1,41 +1,105 @@ import { useNavigate } from 'react-router-dom'; -import { Approve, Flex, Text } from '@duri-fe/ui'; +import { Approve, Flex, Text, theme } from '@duri-fe/ui'; import styled from '@emotion/styled'; -export const DesignerInfo = () => { +interface DesignerInfoProps { + version?: 'vertical' | 'horizontal'; + designerId: number | string; + name: string; + age: number; + gender: string; + experience: number; + roles: string[]; + imageUrl: string; + padding?: string; +} + +export const DesignerInfo = ({ + version = 'vertical', + designerId, + name, + age, + gender, + experience, + roles, + imageUrl, + padding, +}: DesignerInfoProps) => { const navigate = useNavigate(); - const moveToDetail = (designerId: number | string) => { - navigate(`/portfolio/${designerId}`); + + const moveToPortfolio = () => { + if (version === 'vertical') { + navigate(`/portfolio/${designerId}`); + } }; + return ( - moveToDetail(1)}> - - - 김댕댕 - - 경력 5년,30세,남성 - - - {['반려견 스타일리스트', '펫테이너'].map((item, idx) => ( - - {item} - - - ))} + + + + + + + {name} + + {`경력 ${experience}년, ${age}세, ${gender}`} + + + {roles.map((item, idx) => ( + + + {item} + + + + ))} + - + ); }; -const DesignerImg = styled.img` - display: flex; - width: 160px; - height: 160px; - border-radius: 8px; +const Container = styled(Flex)<{ + version: 'vertical' | 'horizontal'; + clickable: boolean; +}>` + cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')}; +`; + +const DesignerImg = styled.img<{ version: 'vertical' | 'horizontal' }>` + width: ${({ version }) => (version === 'horizontal' ? '124px' : '160px')}; + height: ${({ version }) => (version === 'horizontal' ? '124px' : '160px')}; + border-radius: ${({ version }) => + version === 'horizontal' ? '99px' : '8px'}; object-fit: cover; `; + +const ImageWrapper = styled.div<{ version: 'vertical' | 'horizontal' }>` + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +`; + +// 역할 태그 스타일 +const Role = styled(Flex)` + justify-content: flex-start; + align-items: center; + gap: 8px; +`; diff --git a/apps/duri/src/components/shop/PortfolioPhotos.tsx b/apps/duri/src/components/shop/PortfolioPhotos.tsx new file mode 100644 index 00000000..f96dcc23 --- /dev/null +++ b/apps/duri/src/components/shop/PortfolioPhotos.tsx @@ -0,0 +1,46 @@ +import { useNavigate } from 'react-router-dom'; + +import { Flex } from '@duri-fe/ui'; +import styled from '@emotion/styled'; + +interface PortfolioPhotosProps { + portfolios: { id: number; src: string }[]; + designerId: string | number; +} + +export const PortfolioPhotos = ({ + portfolios, + designerId, +}: PortfolioPhotosProps) => { + const navigate = useNavigate(); + + const moveToProfolioDetail = (id: number) => { + navigate(`/portfolio/${designerId}/${id}`); + }; + return ( + + + {portfolios.map((item, index) => ( + moveToProfolioDetail(item.id)} + /> + ))} + + + ); +}; + +const PhotoGrid = styled.div` + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 3px; +`; + +const PortfolioInsideImg = styled.img` + width: 120px; + height: 120px; + object-fit: cover; +`; diff --git a/apps/duri/src/components/shop/SendRequesQBox.tsx b/apps/duri/src/components/shop/SendRequesQBox.tsx new file mode 100644 index 00000000..2ef77ff6 --- /dev/null +++ b/apps/duri/src/components/shop/SendRequesQBox.tsx @@ -0,0 +1,77 @@ +import { useNavigate } from 'react-router-dom'; + +import { + Button, + HeightFitFlex, + NextArrow, + RelativeFlex, + SendColor, + Text, + theme, + WidthFitFlex, +} from '@duri-fe/ui'; +import styled from '@emotion/styled'; + +export const SendRequestQBox = () => { + const navigate = useNavigate(); + const moveToShopRequest = () => { + navigate('/shop/request'); + }; + return ( + + + + 견적 요청서를 전송하시겠습니까? + + + 선택한 샵에 요청서를 전송합니다. + + + + 요청서 선택 + + 작성한 요청서가 없습니다. + + + 작성하러가기 + + + + + + + + 취소 + + + + 확인 + + + + + ); +}; +const AbsoluteBtnWrapper = styled(HeightFitFlex)` + position: absolute; + bottom: 0; +`; + +const FlexBtn = styled(Button)<{ flex: string }>` + border-radius: 8px; + flex: ${({ flex }) => flex}; +`; diff --git a/apps/duri/src/components/shop/ShopInfo.tsx b/apps/duri/src/components/shop/ShopInfo.tsx index c176c66e..1a292aa5 100644 --- a/apps/duri/src/components/shop/ShopInfo.tsx +++ b/apps/duri/src/components/shop/ShopInfo.tsx @@ -1,128 +1,209 @@ -import salonDefault from '@assets/images/pngs/salonDefault.png'; +import { BottomSheet } from 'react-spring-bottom-sheet'; +import { useNavigate } from 'react-router-dom'; + import { Call, + DownArrow, FilledLocation, Flex, + FrontBtn, + HardText, HeightFitFlex, + Image, + RatingStars, + Send, Star, Text, theme, Time, WidthFitFlex, } from '@duri-fe/ui'; +import { PetInfo } from '@duri-fe/ui'; +import { useBottomSheet } from '@duri-fe/utils'; import styled from '@emotion/styled'; import { DesignerInfo } from './DesignerInfo'; +import { SendRequestQBox } from './SendRequesQBox'; import { ShopPhotos } from './ShopPhotos'; export const ShopInfo = () => { + const navigate = useNavigate(); + const { openSheet, bottomSheetProps } = useBottomSheet({ + maxHeight: 556, + }); + return ( - - - {/**헤더 */} - - - 댕댕샵 - - - 4.9 (120) - - - - - - - {`354m | `} - 주소 - - - - - - - 02-111-1111 - - - - - - - - - - 안녕하세요!
- 꼼꼼하고 소중히 미용하는 댕댕샵입니다. -
-
- - {/**디자이너 */} - 디자이너 소개 - - - {/**샵 내부 */} - 샵 내부 - - - {/**리뷰 */} - - 리뷰 - - 4.9 (120) - - + - - - - - - 사용자 이름 - - + navigate(-1)}> + + + + + {/**헤더 */} + + + 댕댕샵 + + + 4.9 (120) - - - 2024-12-26 - - - 후기를 작성하는 곳 ~~ 아주 좋았습니다 +
+ + + + + {`354m | `} + 서울특별시 강남구 188-16 101호 + + + + + + + 02-111-1111 + + + + + + + - - - 신참이 + + 안녕하세요!
+ 꼼꼼하고 소중히 미용하는 댕댕샵입니다. +
+
+ + {/**디자이너 */} + + 디자이너 소개 + + + + {/**샵 내부 */} + + 샵 내부 + + + + {/**리뷰 */} + + + 리뷰 + + 4.2 + + (120) + + + - 시츄, 암컷, 7세, - 7.3kg + + + + + 사용자 이름 + + + + + + 2024-12-26 + - + + 후기를 작성하는 곳 ~~ 아주 좋았습니다. 후기를작성하는 + 칸입니다.후기를작성하는 칸입니다.후기를작성하는 칸입니다. + + + + + - - + + + + + 요청서 보내기 + + + + + + ); }; const ShopInfoContainer = styled(Flex)` @@ -148,20 +229,6 @@ const MainImg = styled.img` object-fit: cover; `; -const ReviewerImg = styled.img` - display: flex; - width: 34px; - height: 34px; - border-radius: 99px; -`; - -const PetImg = styled.img` - display: flex; - width: 77px; - height: 77px; - border-radius: 99px; -`; - const ShadowFlex = styled(HeightFitFlex)` box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1); `; diff --git a/apps/duri/src/components/shop/ShopList.tsx b/apps/duri/src/components/shop/ShopList.tsx index 96bd09ba..d0162309 100644 --- a/apps/duri/src/components/shop/ShopList.tsx +++ b/apps/duri/src/components/shop/ShopList.tsx @@ -17,8 +17,7 @@ import { import { ShopInfoType, useBottomSheet } from '@duri-fe/utils'; import styled from '@emotion/styled'; -import 'react-spring-bottom-sheet/dist/style.css'; - +import { SendRequestQBox } from './SendRequesQBox'; import { ShopLine } from './ShopLine'; interface ShopListProps { @@ -32,9 +31,17 @@ export const ShopList = ({ filter, onFilterChange, }: ShopListProps) => { - const { openSheet, bottomSheetProps } = useBottomSheet({ - maxHeight: 260, - }); + // 필터용 + const { openSheet: openFilterSheet, bottomSheetProps: filterSheetProps } = + useBottomSheet({ + maxHeight: 260, + }); + + // 요청서 전송용 + const { openSheet: openRequestSheet, bottomSheetProps: requestSheetProps } = + useBottomSheet({ + maxHeight: 552, + }); // 선택된 가게 취합용 const [selectedShops, setSelectedShops] = useState([]); @@ -61,7 +68,7 @@ export const ShopList = ({ borderRadius="99px" padding="10px" shadow={'0px 0px 4px 0px rgba(0, 0, 0, 0.25)'} - onClick={openSheet} + onClick={openFilterSheet} > @@ -145,7 +153,7 @@ export const ShopList = ({ ) : null} - + + + + ); diff --git a/apps/duri/src/components/shop/index.tsx b/apps/duri/src/components/shop/index.tsx index e4431002..e57cc694 100644 --- a/apps/duri/src/components/shop/index.tsx +++ b/apps/duri/src/components/shop/index.tsx @@ -3,3 +3,5 @@ export { ShopList } from './ShopList'; export { ShopLine } from './ShopLine'; export { ShopInfo } from './ShopInfo'; export { DesignerInfo } from './DesignerInfo'; +export { ShopPhotos } from './ShopPhotos'; +export { PortfolioPhotos } from './PortfolioPhotos'; diff --git a/apps/duri/src/pages/Shop/Portfolio.tsx b/apps/duri/src/pages/Shop/Portfolio.tsx index e6ea87d2..6d13dadb 100644 --- a/apps/duri/src/pages/Shop/Portfolio.tsx +++ b/apps/duri/src/pages/Shop/Portfolio.tsx @@ -1,12 +1,14 @@ import { useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { DesignerInfo, PortfolioPhotos } from '@duri/components/shop'; import { - AbsoluteFlex, + DuriNavbar, FilledHeart, + Flex, Heart, HeightFitFlex, MobileLayout, - RelativeFlex, Text, theme, WidthFitFlex, @@ -16,17 +18,54 @@ import styled from '@emotion/styled'; const Portfolio = () => { const [isMarked, setIsMarked] = useState(false); + // image dummy + const { designerId } = useParams<{ designerId: string }>(); + + const images = [ + { + id: 1, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + { + id: 2, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + { + id: 3, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + { + id: 4, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + { + id: 6, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + { + id: 7, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + { + id: 8, + src: 'https://s3-alpha-sig.figma.com/img/7a9d/1693/e6a098242d4a2c8446d1acc0d8bf51ab?Expires=1734912000&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=oWIr3Sr2va~UzNKEF4BG2jr3NWDieuXmdrJOaLxpHdcMJKypZi9sN3TyZQCj60ZIlgmzE8Ntj-6~sQBDL1N719Z5AI7J6~WtCi9mWR6jRRNoIxUALcUvZ1lmTuHeywMpKYDzPRbebB~KbJSCv3JphfMpuGEUeS~E3MuLPwsaexSdVtpfcUQg3uYmS3-qPMxnwym0oUbYBPK0xJD28yK3ZjfiMm~FtHSnXUmXegJ4Bp74sYndmHEF1MQKtVfy7h5N-ugtkTT9LuuLerthz26tNe8h4kYfEE9edM7puOyXCIH5Xgh4lNzt4WGD0ObsbUS8XkYpXrTiobSniqq~vnYUHg__', + }, + ]; + return ( - + - + - 댕댕샵 + + 댕댕샵 + setIsMarked(!isMarked)} @@ -37,11 +76,30 @@ const Portfolio = () => { )} - - 경기도 성남시 불정로 119 - - + + 경기도 성남시 불정로 119 + + + + + + + {designerId && ( + + )} + + ); }; @@ -49,12 +107,38 @@ const Portfolio = () => { export default Portfolio; const MainImg = styled.img` + position: absolute; width: 100%; - position: relative; aspect-ratio: 375 / 310; object-fit: cover; + z-index: -1; +`; + +const HeaderBox = styled(Flex)` + position: relative; + z-index: 1; + aspect-ratio: 375 / 310; + height: auto; + + &::before { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 70%; + background: linear-gradient( + 180deg, + rgba(217, 217, 217, 0) 0%, + ${theme.palette.Black} 100% + ); + } `; -const Gradation = styled.div` - background: linear-gradient(180deg, rgba(217, 217, 217, 0) 0%, #111 100%); +const TextBox = styled(Flex)` + position: absolute; + width: fit-content; + height: fit-content; + left: 20px; + bottom: 36px; `; diff --git a/apps/duri/src/pages/Shop/PortfolioDetail.tsx b/apps/duri/src/pages/Shop/PortfolioDetail.tsx new file mode 100644 index 00000000..69f2decb --- /dev/null +++ b/apps/duri/src/pages/Shop/PortfolioDetail.tsx @@ -0,0 +1,97 @@ +// import { useParams } from 'react-router-dom'; + +import { useNavigate } from 'react-router-dom'; + +import { + DuriNavbar, + Flex, + HardText, + Header, + HeightFitFlex, + Image, + MobileLayout, + RelativeFlex, + Text, + theme, + WidthFitFlex, +} from '@duri-fe/ui'; +import styled from '@emotion/styled'; + +const PortfolioDetail = () => { + const navigate = useNavigate(); + + return ( + + + navigate(-1)} + /> + + + + + + {/** 피드백 및 후기 */} + + + + + + 김댕댕 + + + 2024-12-25 + + + + + + + 너무 행복했던 뽀삐와의 미용이 있었어요 :D 너무 얌전하게 미용 + 잘받고간 우리 뽀삐에게 박수^~^ 뽀삐 너무 귀여워요 우리 뽀삐 최고~ + + + + + + + + ); +}; + +export default PortfolioDetail; + +const AbsoluteHeader = styled(Header)` + position: absolute; + z-index: 2; +`; + +const AbsoluteWrapper = styled(HeightFitFlex)` + position: absolute; + top: 0; + left: 0; + z-index: 0; +`; + +const LetterBox = styled(Flex)` + border-radius: 0px 16px 16px 16px; +`; diff --git a/apps/salon/src/pages/Quotation/index.tsx b/apps/salon/src/pages/Quotation/index.tsx index 18013f5d..8f9fc1c1 100644 --- a/apps/salon/src/pages/Quotation/index.tsx +++ b/apps/salon/src/pages/Quotation/index.tsx @@ -1,28 +1,49 @@ -import { Card, Flex, MobileLayout, PetInfo, SalonNavbar, theme } from "@duri-fe/ui" -import { TabBarItem } from "@salon/components/quotation/TabBarItem" +import { + Card, + Flex, + MobileLayout, + PetInfo, + SalonNavbar, + theme, +} from '@duri-fe/ui'; +import { TabBarItem } from '@salon/components/quotation/TabBarItem'; export const QuotationPage = () => { return ( - - - + + + - - - + + + - @@ -30,5 +51,5 @@ export const QuotationPage = () => { - ) -} \ No newline at end of file + ); +}; diff --git a/packages/ui/src/assets/BeforeArrow.tsx b/packages/ui/src/assets/BeforeArrow.tsx index c25bd643..04a6c09f 100644 --- a/packages/ui/src/assets/BeforeArrow.tsx +++ b/packages/ui/src/assets/BeforeArrow.tsx @@ -7,8 +7,8 @@ const SvgBeforeArrow = (props: React.SVGProps) => ( {...props} > diff --git a/packages/ui/src/assets/SendColor.tsx b/packages/ui/src/assets/SendColor.tsx new file mode 100644 index 00000000..00e3c42a --- /dev/null +++ b/packages/ui/src/assets/SendColor.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +const SvgSendColor = (props: React.SVGProps) => ( + + + + + +); +export default SvgSendColor; diff --git a/packages/ui/src/assets/index.tsx b/packages/ui/src/assets/index.tsx index f75e657b..ffae693d 100644 --- a/packages/ui/src/assets/index.tsx +++ b/packages/ui/src/assets/index.tsx @@ -1,3 +1,4 @@ +export { default as SendColor } from './SendColor'; export { default as Add } from './Add'; export { default as AddNew } from './AddNew'; export { default as Approve } from './Approve'; @@ -111,6 +112,7 @@ import SecurityWarning from './SecurityWarning'; import SelectBox from './SelectBox'; import SelectBoxUn from './SelectBoxUn'; import Send from './Send'; +import SendColor from './SendColor'; import Shield from './Shield'; import Shopping from './Shopping'; import Star from './Star'; @@ -160,6 +162,7 @@ export const icons = { CurLocation, Notification, FilledNotification, + SendColor, Report, FilledReport, Menu, diff --git a/packages/ui/src/assets/svgs/Time.svg b/packages/ui/src/assets/svgs/Time.svg deleted file mode 100644 index 4abc17d7..00000000 --- a/packages/ui/src/assets/svgs/Time.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/components/MobileLayout/MobileLayout.tsx b/packages/ui/src/components/MobileLayout/MobileLayout.tsx index 9710415a..12fe32d7 100644 --- a/packages/ui/src/components/MobileLayout/MobileLayout.tsx +++ b/packages/ui/src/components/MobileLayout/MobileLayout.tsx @@ -26,7 +26,10 @@ export const MobileLayout = ({ }; const Container = styled(Flex)` - max-width: 375px; min-height: 100vh; box-sizing: border-box; + + @media (min-width: 420px) { + max-width: 375px; + } `; diff --git a/packages/ui/src/components/ProfileImage/ProfileImage.tsx b/packages/ui/src/components/ProfileImage/ProfileImage.tsx index 9d2f5fc7..da8bcc61 100644 --- a/packages/ui/src/components/ProfileImage/ProfileImage.tsx +++ b/packages/ui/src/components/ProfileImage/ProfileImage.tsx @@ -1,5 +1,5 @@ -import { Flex, Profile, theme } from "@duri-fe/ui"; -import styled from "@emotion/styled"; +import { Flex, Image, Profile, theme } from '@duri-fe/ui'; +import styled from '@emotion/styled'; interface ProfileImageProps { width: number; @@ -14,22 +14,34 @@ export const ProfileImage = ({ height, borderRadius, src, - iconSize = 52 + iconSize = 52, }: ProfileImageProps) => { - return ( - src ? ( - - 프로필 사진 - - ) : ( - - - - ) - ) -} + return src ? ( + + 프로필 사진 + + ) : ( + + + + ); +}; const ProfileContainer = styled(Flex)` flex-shrink: 0; overflow: hidden; -` \ No newline at end of file +`; diff --git a/packages/ui/src/components/Quotation/PetInfo.tsx b/packages/ui/src/components/Quotation/PetInfo.tsx index 84dbe046..31eb9a74 100644 --- a/packages/ui/src/components/Quotation/PetInfo.tsx +++ b/packages/ui/src/components/Quotation/PetInfo.tsx @@ -2,6 +2,7 @@ import { diseaseMapping, Flex, HeightFitFlex, + KeyOfTypo, personalityMapping, ProfileImage, SalonTag, @@ -16,11 +17,10 @@ interface PetInfoType { breed: string; weight: number; gender: string; + themeVariant?: 'compact' | 'spacious' | 'medium'; neutering?: boolean; character?: string[]; diseases?: string[]; - imageSize?: number; - imageBorderRadius?: number; } export const PetInfo = ({ @@ -33,47 +33,95 @@ export const PetInfo = ({ neutering, character, diseases, - imageSize = 133, - imageBorderRadius = 40, + themeVariant = 'spacious', }: PetInfoType) => { + const { imageSize, gap, typo } = PetInfoTheme[themeVariant]; + return ( - - - {name} - + + + {name} + {breed}, {gender === 'F' ? '암컷' : '수컷'}, {age}세, {weight}kg {neutering && } - {character && - {character.map((key, index) => { - const label = personalityMapping[key] - return - })} - } - {diseases && - {diseases.map((key, index) => { - const label = diseaseMapping[key] - return - })} - } + {character && ( + + {character.map((key, index) => { + const label = personalityMapping[key]; + return ( + + ); + })} + + )} + {diseases && ( + + {diseases.map((key, index) => { + const label = diseaseMapping[key]; + return ( + + ); + })} + + )} ); }; + +interface ThemeVariant { + imageSize: { + width: number; + height: number; + borderRadius: number; + }; + gap: { + vertical: number; + horizontal: number; + }; + typo: { + name: KeyOfTypo; + description: KeyOfTypo; + }; +} + +const PetInfoTheme: Record<'compact' | 'spacious' | 'medium', ThemeVariant> = { + compact: { + imageSize: { width: 77, height: 77, borderRadius: 99 }, + gap: { vertical: 20, horizontal: 6 }, + typo: { name: 'Label1', description: 'Label3' }, + }, + medium: { + imageSize: { width: 100, height: 100, borderRadius: 8 }, + gap: { vertical: 18, horizontal: 6 }, + typo: { name: 'Body2', description: 'Caption2' }, + }, + spacious: { + imageSize: { width: 133, height: 133, borderRadius: 40 }, + gap: { vertical: 18, horizontal: 8 }, + typo: { name: 'Title3', description: 'Body3' }, + }, +}; diff --git a/packages/ui/src/components/RatingStars/RatingStars.tsx b/packages/ui/src/components/RatingStars/RatingStars.tsx new file mode 100644 index 00000000..097d08d6 --- /dev/null +++ b/packages/ui/src/components/RatingStars/RatingStars.tsx @@ -0,0 +1,18 @@ +import { Star, WidthFitFlex } from '@duri-fe/ui'; + +interface RatingStarsProps { + score: number; + size: number; +} + +export const RatingStars = ({ score, size }: RatingStarsProps) => { + const fullStars = Math.round(score); + + return ( + + {Array.from({ length: fullStars }).map((_, idx) => ( + + ))} + + ); +}; diff --git a/packages/ui/src/components/RatingStars/index.tsx b/packages/ui/src/components/RatingStars/index.tsx new file mode 100644 index 00000000..d2bbd2f9 --- /dev/null +++ b/packages/ui/src/components/RatingStars/index.tsx @@ -0,0 +1 @@ +export { RatingStars } from './RatingStars'; diff --git a/packages/ui/src/components/index.tsx b/packages/ui/src/components/index.tsx index c0f0c863..bc70f808 100644 --- a/packages/ui/src/components/index.tsx +++ b/packages/ui/src/components/index.tsx @@ -17,3 +17,4 @@ export * from './Toast'; export * from './Modal'; export * from './ProfileImage'; export * from './Quotation'; +export * from './RatingStars'; diff --git a/packages/ui/src/stories/styles/Typo.mdx b/packages/ui/src/stories/styles/Typo.mdx index d504b4ce..126daf3d 100644 --- a/packages/ui/src/stories/styles/Typo.mdx +++ b/packages/ui/src/stories/styles/Typo.mdx @@ -132,3 +132,14 @@ import { theme } from '../../styles'; sampleText={'Body4: This is a sample text.'} fontFamily={'Pretendard'} /> + +
+ +## Letter + + diff --git a/packages/ui/src/styles/typo.tsx b/packages/ui/src/styles/typo.tsx index f3fead77..db60ae50 100644 --- a/packages/ui/src/styles/typo.tsx +++ b/packages/ui/src/styles/typo.tsx @@ -5,6 +5,7 @@ export const calcRem = (px: number) => `${px / 16}rem`; * @param Title1: 페이지 제목 타이틀 * @param Title2: 본문 타이틀 * @param Title3: 박스 안에 들어가는 타이틀 + * @param Title4: 가게 상세 페이지 타이틀 * * @param Caption1: 타이틀 위/아래 부가설명 텍스트 * @param Caption2: 거리표시 텍스트 @@ -75,6 +76,13 @@ export const typo = { font-weight: 600; line-height: normal; `, + Title4: css` + /* 가게 상세 타이틀 */ + font-family: 'Pretendard'; + font-size: ${calcRem(22)}; + font-weight: 600; + line-height: normal; + `, Caption1: css` /* 타이틀 위/아래 부가설명 텍스트 */ font-family: 'Pretendard'; @@ -84,7 +92,6 @@ export const typo = { `, Caption2: css` /* 거리표시 텍스트 */ - font-family: 'Pretendard'; font-size: ${calcRem(13)}; font-weight: 500; diff --git a/packages/utils/src/hooks/useBottomSheet.ts b/packages/utils/src/hooks/useBottomSheet.ts index 7504c432..a75297a1 100644 --- a/packages/utils/src/hooks/useBottomSheet.ts +++ b/packages/utils/src/hooks/useBottomSheet.ts @@ -42,11 +42,14 @@ const StyledBottomCss = css` [data-rsbs-root]::after { border-radius: 16px 16px 0px 0px; z-index: 20; - max-width: 375px; + --max-width: 375px; - @media (min-width: 480px) { - left: calc(50% - 187.5px); + @media (max-width: 420px) { + --max-width: 100%; } + + max-width: var(--max-width); + left: calc(50% - (var(--max-width) / 2)); } [data-rsbs-backdrop] {