diff --git a/package-lock.json b/package-lock.json
index 46dc96c..40ade3e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "concept-be-design-system",
- "version": "0.3.9",
+ "version": "0.4.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "concept-be-design-system",
- "version": "0.3.9",
+ "version": "0.4.8",
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
diff --git a/package.json b/package.json
index 9b5d811..42e7d12 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "concept-be-design-system",
"description": "컨셉비 디자인 시스템",
- "version": "0.4.5",
+ "version": "0.4.8",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
diff --git a/src/App.tsx b/src/App.tsx
index 5b3696c..9a975ba 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
-import { Spacer } from '.';
+import { Button, Spacer } from '.';
import Child from './Child';
import CheckboxContainer from './components/CheckboxContainer/CheckboxContainer';
import Dropdown from './components/Dropdown/Dropdown';
@@ -149,6 +149,8 @@ const App = () => {
))}
+
+
-
-
-
diff --git a/src/assets/svg/login/default_profile.svg b/src/assets/svg/login/default_profile.svg
deleted file mode 100644
index ef2da74..0000000
--- a/src/assets/svg/login/default_profile.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/assets/svg/profile/book_open.svg b/src/assets/svg/profile/book_open.svg
new file mode 100644
index 0000000..eec694a
--- /dev/null
+++ b/src/assets/svg/profile/book_open.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/svg/profile/message_dots_circle.svg b/src/assets/svg/profile/message_dots_circle.svg
new file mode 100644
index 0000000..892d032
--- /dev/null
+++ b/src/assets/svg/profile/message_dots_circle.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/Badge/Badge.tsx b/src/components/Badge/Badge.tsx
index e4319cd..d63c65c 100644
--- a/src/components/Badge/Badge.tsx
+++ b/src/components/Badge/Badge.tsx
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
-import { ComponentPropsWithoutRef, ElementType } from 'react';
+import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';
import { ColorType } from '../../styles/theme';
@@ -10,7 +10,7 @@ type Props = {
as?: T;
backgroundColor?: BackgroundColorType;
fontColor?: FontColorType;
- children: string;
+ children: ReactNode;
} & ComponentPropsWithoutRef;
const Badge = ({
diff --git a/src/components/BottomSheet/BottomSheet.tsx b/src/components/BottomSheet/BottomSheet.tsx
index 2cf66df..3bdb083 100644
--- a/src/components/BottomSheet/BottomSheet.tsx
+++ b/src/components/BottomSheet/BottomSheet.tsx
@@ -33,16 +33,18 @@ const BottomSheetWrapper = styled.div<{ isOpen: boolean }>`
bottom: ${(props) => (props.isOpen ? '0' : '-100vh')};
left: 0;
right: 0;
+ margin: 0 auto;
+ width: auto;
+ height: max-content;
+ max-width: 420px;
+ max-height: 90%;
+ min-height: 70%;
background-color: #fff;
- height: 80%;
- transition: bottom 0.3s ease-in-out;
- overflow: auto;
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.2);
- z-index: 9999;
border-radius: 14px 14px 0 0;
- max-width: 375px;
- width: auto;
- margin: 0 auto;
+ overflow: auto;
+ z-index: 9999;
+ transition: bottom 0.3s ease-in-out;
`;
const Overlay = styled.div`
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
index c976e47..0fce687 100644
--- a/src/components/Button/Button.tsx
+++ b/src/components/Button/Button.tsx
@@ -1,49 +1,48 @@
import styled from '@emotion/styled';
-import {
- ComponentPropsWithoutRef,
- ReactNode,
- ElementType,
- MouseEventHandler,
-} from 'react';
-type Props = {
- children: ReactNode;
- as?: T;
- onClick?: MouseEventHandler;
- isGrayOut?: boolean;
-} & ComponentPropsWithoutRef;
-
-const Button = ({
- as,
- onClick = () => {},
- isGrayOut = false,
- children,
- ...attributes
-}: Props) => {
- const tag = as || 'button';
+import { convertCSS } from '../..';
- return (
-
- {children}
-
- );
-};
-
-export default Button;
+export interface Props {
+ width?: number | string;
+ height?: number | string;
+ minWidth?: number | string;
+ minHeight?: number | string;
+ maxWidth?: number | string;
+ maxHeight?: number | string;
+ padding?: string;
+ paddingTop?: number | string;
+ paddingRight?: number | string;
+ paddingBottom?: number | string;
+ paddingLeft?: number | string;
+ isGrayOut?: boolean;
+}
-const Wrapper = styled.button<{ isGrayOut: boolean }>`
+const Button = styled.button`
display: flex;
justify-content: center;
align-items: center;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ width: ${({ width }) => (width ? convertCSS(width) : '100%')};
+ height: ${({ height }) => height && convertCSS(height)};
+ min-width: ${({ minWidth }) => minWidth && convertCSS(minWidth)};
+ min-height: ${({ minHeight }) => minHeight && convertCSS(minHeight)};
+ max-width: ${({ maxWidth }) => maxWidth && convertCSS(maxWidth)};
+ max-height: ${({ maxHeight }) => maxHeight && convertCSS(maxHeight)};
background-color: ${({ isGrayOut, theme }) =>
isGrayOut ? theme.color.bg1 : theme.color.c1};
color: ${({ isGrayOut, theme }) =>
isGrayOut ? theme.color.b : theme.color.w1};
- border: none;
- border-radius: 6px;
font-size: ${({ theme }) => theme.font.suit16sb.fontSize}px;
font-weight: ${({ theme }) => theme.font.suit16sb.fontWeight};
- width: 100%;
- padding: 17px 28px;
- cursor: pointer;
+ padding: ${({ padding }) => (padding ? padding : '17px 28px')};
+ padding-top: ${({ paddingTop }) => paddingTop && convertCSS(paddingTop)};
+ padding-right: ${({ paddingRight }) =>
+ paddingRight && convertCSS(paddingRight)};
+ padding-bottom: ${({ paddingBottom }) =>
+ paddingBottom && convertCSS(paddingBottom)};
+ padding-left: ${({ paddingLeft }) => paddingLeft && convertCSS(paddingLeft)};
`;
+
+export default Button;
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
index 935a46f..0c74417 100644
--- a/src/components/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -35,7 +35,7 @@ const Wrapper = styled.header<{ main?: boolean }>`
position: fixed;
box-sizing: border-box;
width: 100%;
- max-width: 375px;
+ max-width: 420px;
top: 0;
z-index: 1;
`;
diff --git a/src/components/ImageView/ImageView.tsx b/src/components/ImageView/ImageView.tsx
new file mode 100644
index 0000000..9a6426d
--- /dev/null
+++ b/src/components/ImageView/ImageView.tsx
@@ -0,0 +1,58 @@
+import styled from '@emotion/styled';
+import { ImgHTMLAttributes, SyntheticEvent } from 'react';
+
+import { convertCSS } from '../..';
+
+interface Props extends ImgHTMLAttributes {
+ width?: number | string;
+ height?: number | string;
+ maxWidth?: number | string;
+ maxHeight?: number | string;
+ objectFit?: string;
+ borderRadius?: number | string;
+ ratio?: string;
+ defaultSrc?: string;
+}
+const ImageView = ({
+ src,
+ alt,
+ width = '100%',
+ height = '100%',
+ maxWidth,
+ maxHeight,
+ objectFit = 'cover',
+ borderRadius,
+ ratio,
+ defaultSrc,
+}: Props) => {
+ return (
+ ) => {
+ if (defaultSrc) e.currentTarget.src = defaultSrc;
+ }}
+ />
+ );
+};
+
+const StyledImage = styled.img`
+ display: block;
+ width: ${({ width }) => width && convertCSS(width)};
+ height: ${({ height }) => height && convertCSS(height)};
+ max-width: ${({ maxWidth }) => maxWidth && convertCSS(maxWidth)};
+ max-height: ${({ maxHeight }) => maxHeight && convertCSS(maxHeight)};
+ object-fit: ${({ objectFit }) => objectFit};
+ border-radius: ${({ borderRadius }) =>
+ borderRadius && convertCSS(borderRadius)};
+ aspect-ratio: ${({ ratio }) => ratio};
+`;
+
+export default ImageView;
diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx
index f592b6b..aa17262 100644
--- a/src/components/Navigation/Navigation.tsx
+++ b/src/components/Navigation/Navigation.tsx
@@ -28,7 +28,7 @@ const Wrapper = styled.div`
width: 100%;
left: 50%;
transform: translateX(-50%);
- max-width: 375px;
+ max-width: 420px;
`;
const NavBackImg = styled.img`
diff --git a/src/components/TabLayout/TabLayout.tsx b/src/components/TabLayout/TabLayout.tsx
index 5494ca6..ed71414 100644
--- a/src/components/TabLayout/TabLayout.tsx
+++ b/src/components/TabLayout/TabLayout.tsx
@@ -11,14 +11,18 @@ interface TabProps {
interface Props {
width?: number | string;
+ maxWidth?: number | string;
height?: number | string;
+ maxHeight?: number | string;
tabBoxHeight?: number | string;
children: ReactNode;
}
const TabLayout = ({
- width = 375,
- height = 400,
+ width,
+ maxWidth,
+ height,
+ maxHeight,
tabBoxHeight = 50,
children,
...attributes
@@ -29,7 +33,7 @@ const TabLayout = ({
const [position, setPosition] = useState(0);
return (
-
+
{childrenElements.map((children, idx) => (
position === idx && (
-
+
{children}
),
@@ -57,8 +61,9 @@ TabLayout.Tab = Tab;
export default TabLayout;
-const Wrapper = styled.div<{ width: number | string }>`
+const Wrapper = styled.div>`
width: ${({ width }) => width && convertCSS(width)};
+ max-width: ${({ maxWidth }) => maxWidth && convertCSS(maxWidth)};
margin: 0 auto;
position: relative;
`;
@@ -84,7 +89,8 @@ const TabBox = styled.div<{ active: boolean }>`
box-sizing: border-box;
`;
-const TabPanel = styled.div<{ height: number | string }>`
+const TabPanel = styled.div>`
width: 100%;
height: ${({ height }) => height && convertCSS(height)};
+ max-height: ${({ maxHeight }) => maxHeight && convertCSS(maxHeight)};
`;
diff --git a/src/index.ts b/src/index.ts
index df3a249..35c018d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,8 @@
import PNGAgreementBackground from './assets/image/agreement_bg.png';
import PNGBottomBackground from './assets/image/bottom_bg.png';
+import PNGDefaultProfileInfo100 from './assets/image/default_login_profile.png';
+import PNGDefaultProfileBackground from './assets/image/default_profile_background.png';
+import PNGDefaultProfileInfo36 from './assets/image/default_profile_info.png';
import PNGErrorBackground from './assets/image/error_back.png';
import PNGIdeaBackground1 from './assets/image/idea_back_1.png';
import PNGIdeaBackground2 from './assets/image/idea_back_2.png';
@@ -16,6 +19,7 @@ import Dropdown from './components/Dropdown/Dropdown';
import Field from './components/Field/Field';
import Flex from './components/Flex/Flex';
import Header from './components/Header/Header';
+import ImageView from './components/ImageView/ImageView';
import Navigation from './components/Navigation/Navigation';
import RadioContainer from './components/RadioContainer/RadioContainer';
import Spacer from './components/Spacer/Spacer';
@@ -71,8 +75,6 @@ export { ReactComponent as SVGLoginImageWrite } from './assets/svg/login/image_w
export { ReactComponent as SVGLoginNaver } from './assets/svg/login/naver.svg';
export { ReactComponent as SVGLoginKakao } from './assets/svg/login/kakao.svg';
export { ReactComponent as SVGLoginLogo } from './assets/svg/login/login_logo.svg';
-export { ReactComponent as SVGLoginDefaultImage } from './assets/svg/login/default_image.svg';
-export { ReactComponent as SVGLoginDefaultProfile } from './assets/svg/login/default_profile.svg';
export { ReactComponent as SVGFeedWrite40 } from './assets/svg/feed/write40.svg';
export { ReactComponent as SVGFeedLike } from './assets/svg/feed/like.svg';
@@ -84,6 +86,9 @@ export { ReactComponent as SVGFeedUnLike } from './assets/svg/feed/unlike.svg';
export { ReactComponent as SVGFeedUnScrap } from './assets/svg/feed/unscrap.svg';
export { ReactComponent as SVGMore24 } from './assets/svg/feed/more.svg';
+export { ReactComponent as SVGProfileMessageDots } from './assets/svg/profile/message_dots_circle.svg';
+export { ReactComponent as SVGProfileBookOpen } from './assets/svg/profile/book_open.svg';
+
export {
Badge,
BottomSheet,
@@ -95,6 +100,7 @@ export {
Field,
Flex,
Header,
+ ImageView,
Navigation,
RadioContainer,
Spacer,
@@ -117,4 +123,7 @@ export {
PNGIdeaBackground4,
PNGIdeaBackground5,
PNGErrorBackground,
+ PNGDefaultProfileInfo36,
+ PNGDefaultProfileInfo100,
+ PNGDefaultProfileBackground,
};
diff --git a/src/stories/Badge.stories.tsx b/src/stories/Badge.stories.tsx
index 940b2d2..bceafd1 100644
--- a/src/stories/Badge.stories.tsx
+++ b/src/stories/Badge.stories.tsx
@@ -1,7 +1,7 @@
import { Meta, StoryObj } from '@storybook/react';
import Badge from '../components/Badge/Badge';
-import { useEffect, useRef, useState } from 'react';
+import { ReactNode, useEffect, useRef, useState } from 'react';
const meta = {
title: 'Components/Badge',
@@ -55,7 +55,7 @@ export const Sample: Story = {
},
render: ({ children, backgroundColor, fontColor }) => {
const timerId = useRef(null);
- const [badges, setBadges] = useState([
+ const [badges, setBadges] = useState([
'서비스기획',
'영상디자인',
'시각디자인',
diff --git a/src/stories/Button.stories.tsx b/src/stories/Button.stories.tsx
index 5866e43..c130596 100644
--- a/src/stories/Button.stories.tsx
+++ b/src/stories/Button.stories.tsx
@@ -77,7 +77,7 @@ export const InteractionTest: Story = {
as={as}
isGrayOut
onClick={() => setCount((prev) => prev - 1)}
- customStyle={{ flex: 1 }}
+ style={{ flex: 1 }}
>
감소
@@ -86,7 +86,7 @@ export const InteractionTest: Story = {
as={as}
isGrayOut={isGrayOut}
onClick={() => setCount((prev) => prev + 1)}
- customStyle={{ flex: 2 }}
+ style={{ flex: 2 }}
>
증가
diff --git a/src/stories/ImageView.stories.tsx b/src/stories/ImageView.stories.tsx
new file mode 100644
index 0000000..94a84f1
--- /dev/null
+++ b/src/stories/ImageView.stories.tsx
@@ -0,0 +1,75 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import ImageView from '../components/ImageView/ImageView';
+
+const meta = {
+ title: 'Components/ImageView',
+ component: ImageView,
+ tags: ['autodocs'],
+ argTypes: {
+ src: {
+ control: 'text',
+ description: 'ImageView 컴포넌트의 src를 지정합니다.',
+ },
+ alt: {
+ control: 'text',
+ description: 'ImageView 컴포넌트의 alt를 지정합니다.',
+ },
+ width: {
+ control: 'number',
+ description:
+ 'ImageView 컴포넌트의 가로 크기를 설정합니다. 기본값은 100% 입니다.',
+ },
+ height: {
+ control: 'number',
+ description:
+ 'ImageView 컴포넌트의 세로 크기를 설정합니다. 기본값은 100% 입니다.',
+ },
+ maxWidth: {
+ control: 'number',
+ description: 'ImageView 컴포넌트의 가로 최대 크기를 설정합니다.',
+ },
+ maxHeight: {
+ control: 'number',
+ description: 'ImageView 컴포넌트의 세로 최대 크기를 설정합니다.',
+ },
+ objectFit: {
+ control: 'inline-radio',
+ options: ['fill', 'contain', 'cover'],
+ description:
+ 'ImageView 컴포넌트의 이미지 표현 방식을 설정합니다. 기본값은 cover 입니다.',
+ },
+ borderRadius: {
+ control: 'number',
+ description: 'ImageView 컴포넌트의 Border Radius를 설정합니다.',
+ },
+ defaultSrc: {
+ control: 'text',
+ description:
+ 'ImageView 컴포넌트의 src 표시 중 이미지 부재 등의 오류로 에러 발생 시 대체할 기본 이미지 주소를 지정합니다.',
+ },
+ },
+} as Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ src: 'https://interactive-examples.mdn.mozilla.net/media/examples/plumeria-146x200.jpg',
+ alt: '이미지 입니다.',
+ width: '100%',
+ height: '100%',
+ maxWidth: undefined,
+ maxHeight: undefined,
+ objectFit: 'cover',
+ borderRadius: undefined,
+ defaultSrc:
+ 'https://upload.wikimedia.org/wikipedia/commons/b/ba/Error-logo.png',
+ },
+ render: (args) => (
+
+
+
+ ),
+};
diff --git a/src/stories/PNGCommon.stories.tsx b/src/stories/PNGCommon.stories.tsx
index a51feb6..dfd8908 100644
--- a/src/stories/PNGCommon.stories.tsx
+++ b/src/stories/PNGCommon.stories.tsx
@@ -3,6 +3,9 @@ import { Meta, StoryObj } from '@storybook/react';
import {
PNGAgreementBackground,
PNGBottomBackground,
+ PNGDefaultProfileBackground,
+ PNGDefaultProfileInfo100,
+ PNGDefaultProfileInfo36,
PNGIdeaBackground1,
PNGIdeaBackground2,
PNGIdeaBackground3,
@@ -67,6 +70,26 @@ export const Default: Story = {
alt="PNGIdeaBackground5"
/>
+
),
};
diff --git a/src/stories/SVGLogin.stories.tsx b/src/stories/SVGLogin.stories.tsx
index 434df5b..2310b14 100644
--- a/src/stories/SVGLogin.stories.tsx
+++ b/src/stories/SVGLogin.stories.tsx
@@ -4,9 +4,7 @@ import {
SVGLoginNaver,
SVGLoginKakao,
SVGLoginLogo,
- SVGLoginDefaultImage,
SVGLoginImageWrite,
- SVGLoginDefaultProfile,
} from '../.';
const meta = {
@@ -42,8 +40,6 @@ export const Default: Story = {
>
-
-
diff --git a/src/stories/SVGProfile.stories.tsx b/src/stories/SVGProfile.stories.tsx
new file mode 100644
index 0000000..17c4cc7
--- /dev/null
+++ b/src/stories/SVGProfile.stories.tsx
@@ -0,0 +1,20 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { SVGProfileBookOpen, SVGProfileMessageDots } from '../.';
+
+const meta = {
+ title: 'Assets/SVG/Profile',
+ tags: ['autodocs'],
+} as Meta