diff --git a/ui-kit/.storybook/preview.js b/ui-kit/.storybook/preview.js index 99e86174..6ba78858 100644 --- a/ui-kit/.storybook/preview.js +++ b/ui-kit/.storybook/preview.js @@ -1,9 +1,11 @@ import '../src/sass/index.scss'; import React from 'react'; -import { LubyconUIKitProvider } from '../src/components'; +import { LubyconUIKitProvider, Container } from '../src/components'; export const decorators = [(Story => ( - + + + ))]; diff --git a/ui-kit/src/components/Alert/index.tsx b/ui-kit/src/components/Alert/index.tsx new file mode 100644 index 00000000..892ac96e --- /dev/null +++ b/ui-kit/src/components/Alert/index.tsx @@ -0,0 +1,71 @@ +import React, { forwardRef, HTMLAttributes } from 'react'; +import { colors, SemanticColor } from 'src/constants/colors'; +import classnames from 'classnames'; +import Text from '../Text'; +import Icon from '../Icon'; +import { informationCircle, closeCircle, alertCircle, checkmarkCircle } from 'ionicons/icons'; +import { Combine } from 'src/types/utils'; + +interface AlertIcon { + icon: string; + color: string; +} +const alertIconMap: { + [key in SemanticColor]: AlertIcon; +} = { + negative: { + icon: closeCircle, + color: colors.red50, + }, + notice: { + icon: alertCircle, + color: colors.yellow50, + }, + informative: { + icon: informationCircle, + color: colors.blue50, + }, + positive: { + icon: checkmarkCircle, + color: colors.green50, + }, +}; + +type AlertProps = Combine< + { + type?: SemanticColor; + title?: string; + }, + HTMLAttributes +>; + +const Alert = forwardRef(function Alert( + { type = 'informative', title, children, className, ...props }, + ref +) { + const { icon: iconName, color: iconColor } = alertIconMap[type]; + + return ( +
+ + {title ? ( + + {title} + + ) : null} + {children} +
+ ); +}); + +export default Alert; diff --git a/ui-kit/src/components/Card/CardImageContent.tsx b/ui-kit/src/components/Card/CardImageContent.tsx index 32e1acfb..7c5c3da1 100644 --- a/ui-kit/src/components/Card/CardImageContent.tsx +++ b/ui-kit/src/components/Card/CardImageContent.tsx @@ -11,7 +11,7 @@ type CardImageContentProps = Combine< >; const CardImageContent = ({ className, ...props }: CardImageContentProps) => { return ( -
+
); diff --git a/ui-kit/src/components/Container/index.tsx b/ui-kit/src/components/Container/index.tsx index fbbf5e3f..b1b264e4 100644 --- a/ui-kit/src/components/Container/index.tsx +++ b/ui-kit/src/components/Container/index.tsx @@ -1,9 +1,27 @@ import React, { HTMLAttributes } from 'react'; - +import classnames from 'classnames'; interface ContainerProps extends HTMLAttributes { - size: 'fluid' | 'sm' | 'md' | 'lg' | 'xl'; + fluid?: boolean; } -export default function Container({ ...props }: ContainerProps): JSX.Element { - return
{props.children}
; +export default function Container({ + children, + fluid = false, + className, + ...props +}: ContainerProps): JSX.Element { + return ( +
+ {children} +
+ ); } diff --git a/ui-kit/src/components/Container/style.scss b/ui-kit/src/components/Container/style.scss deleted file mode 100644 index 48514080..00000000 --- a/ui-kit/src/components/Container/style.scss +++ /dev/null @@ -1,2 +0,0 @@ -.container { -} diff --git a/ui-kit/src/components/Grid/Column.tsx b/ui-kit/src/components/Grid/Column.tsx index 58935d4c..c9f87978 100644 --- a/ui-kit/src/components/Grid/Column.tsx +++ b/ui-kit/src/components/Grid/Column.tsx @@ -22,7 +22,7 @@ const Column = ( () => sizes.map((size) => { const { [size]: sizeValue } = props; - return sizeValue ? `lubycon-grid-column--${size}__${sizeValue}` : ''; + return sizeValue ? `lubycon-grid-column--${size}--${sizeValue}` : ''; }), [] ); diff --git a/ui-kit/src/components/Grid/types.ts b/ui-kit/src/components/Grid/types.ts index 975e2928..d408b490 100644 --- a/ui-kit/src/components/Grid/types.ts +++ b/ui-kit/src/components/Grid/types.ts @@ -1,5 +1,5 @@ export const DEFAULT_ELEMENT = 'div' as const; type ColumnNumberSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; -export type ColumnSize = boolean | 'auto' | ColumnNumberSize; +export type ColumnSize = 'auto' | ColumnNumberSize; export type ColumnResponsive = 'xl' | 'lg' | 'md' | 'sm' | 'xs'; diff --git a/ui-kit/src/components/Icon/index.tsx b/ui-kit/src/components/Icon/index.tsx index 79fc69d3..b165e6ad 100644 --- a/ui-kit/src/components/Icon/index.tsx +++ b/ui-kit/src/components/Icon/index.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; import classnames from 'classnames'; -import { Colors, colors } from 'src/constants/colors'; +import { colors } from 'src/constants/colors'; /** * UI Kit 내부에서만 사용 @@ -10,10 +10,11 @@ interface Props { icon: string; size?: number; type: 'outline' | 'filled'; - color?: Colors; + color?: string; + className?: string; } -const Icon = ({ icon, size = 16, type, color = colors.gray100 }: Props) => { +const Icon = ({ icon, size = 16, type, color = colors.gray100, className }: Props) => { const svgTag = useMemo(() => { return icon.replace(/data:image\/svg\+xml;utf8,/, ''); }, [icon]); @@ -25,10 +26,14 @@ const Icon = ({ icon, size = 16, type, color = colors.gray100 }: Props) => { return ( diff --git a/ui-kit/src/components/Text/index.tsx b/ui-kit/src/components/Text/index.tsx index c1fa78bc..9f9a525a 100644 --- a/ui-kit/src/components/Text/index.tsx +++ b/ui-kit/src/components/Text/index.tsx @@ -18,10 +18,14 @@ const Text = ( return ( ); diff --git a/ui-kit/src/components/index.ts b/ui-kit/src/components/index.ts index 3932c298..fd2f0ee0 100644 --- a/ui-kit/src/components/index.ts +++ b/ui-kit/src/components/index.ts @@ -1,6 +1,8 @@ +export { default as Alert } from './Alert'; export { default as Button } from './Button'; export { default as Checkbox } from './Checkbox'; export { Row, Column } from './Grid'; +export { default as Container } from './Container'; export { default as Radio } from './Radio'; export { default as Selection } from './Selection'; export { default as Switch } from './Switch'; diff --git a/ui-kit/src/constants/colors.ts b/ui-kit/src/constants/colors.ts index 6f3cdde6..a722bb20 100644 --- a/ui-kit/src/constants/colors.ts +++ b/ui-kit/src/constants/colors.ts @@ -1,29 +1,29 @@ export const colors = { - green50: '#13BC4C', - green40: '#78CF81', - green60: '#0F933C', - blue50: '#135CE9', - blue40: '#87ADF5', - blue60: '#013CAD', - red50: '#CB121C', - red40: '#F29CA1', - red60: '#9B0B13', - yellow50: '#F0CB08', - yellow40: '#F9E681', - yellow60: '#AA8F00', - gray100: '#1B1B1C', - gray90: '#2A2A2C', - gray80: '#4C4D53', - gray70: '#76777D', - gray60: '#8E9095', - gray50: '#B5B6B9', - gray40: '#D0D1D3', - gray30: '#E3E4E5', - gray20: '#F3F4F5', - gray10: '#FCFCFD', + green40: '#dff6e7', + green50: '#13bc4c', + green60: '#00a438', + blue40: '#e6effe', + blue50: '#135ce9', + blue60: '#013cad', + red40: '#fae7e8', + red50: '#cb121c', + red60: '#9b0b13', + yellow40: '#fdf5ce', + yellow50: '#f0ca08', + yellow60: '#aa8f00', + gray100: '#1b1b1c', + gray90: '#2a2a2c', + gray80: '#4c4d53', + gray70: '#76777d', + gray60: '#8e9095', + gray50: '#b5b6b9', + gray40: '#d0d1d3', + gray30: '#e3e4e5', + gray20: '#f3f4f5', + gray10: '#fcfcfd', } as const; -export type SemanticColorName = 'positive' | 'informative' | 'negative' | 'notice'; +export type SemanticColor = 'positive' | 'informative' | 'negative' | 'notice'; export type ColorProperty = keyof typeof colors; diff --git a/ui-kit/src/sass/components/_Alert.scss b/ui-kit/src/sass/components/_Alert.scss new file mode 100644 index 00000000..09b9e091 --- /dev/null +++ b/ui-kit/src/sass/components/_Alert.scss @@ -0,0 +1,29 @@ +$alert-horizental-padding: 14px; + +.lubycon-alert { + display: flex; + justify-content: flex-start; + align-items: center; + border-radius: 4px; + padding: 10px $alert-horizental-padding; + + &--type-negative { + background-color: get-color('red40'); + } + &--type-notice { + background-color: get-color('yellow40'); + } + &--type-informative { + background-color: get-color('blue40'); + } + &--type-positive { + background-color: get-color('green40'); + } + + &__title { + margin-right: 8px; + } + &__icon { + margin-right: $alert-horizental-padding; + } +} diff --git a/ui-kit/src/sass/components/_Column.scss b/ui-kit/src/sass/components/_Column.scss index f98c7a80..04c69ffa 100644 --- a/ui-kit/src/sass/components/_Column.scss +++ b/ui-kit/src/sass/components/_Column.scss @@ -1,15 +1,23 @@ .lubycon-grid-column { position: relative; - width: 100%; padding-right: ($gutter / 2); padding-left: ($gutter / 2); + flex-basis: 0; + flex-grow: 1; + min-width: 0; + max-width: 100%; + box-sizing: border-box; } @each $breakpoint, $size in $breakpoints { + .lubycon-grid-column--#{$breakpoint}--auto { + flex: 0 0 auto; + } + @for $i from 1 through $max-columns { - .lubycon-grid-column--#{$breakpoint}__#{$i} { - @include media-breakpoint($size) { - flex: 0 0 auto; + .lubycon-grid-column--#{$breakpoint}--#{$i} { + @include media-breakpoint($breakpoint) { + flex: 0 0 percentage($i / $max-columns); width: percentage($i / $max-columns); } } diff --git a/ui-kit/src/sass/components/_Container.scss b/ui-kit/src/sass/components/_Container.scss new file mode 100644 index 00000000..4e7deb91 --- /dev/null +++ b/ui-kit/src/sass/components/_Container.scss @@ -0,0 +1,11 @@ +.lubycon-container { + width: 100%; + max-width: none; + margin: 0 auto; + &--fluid { + max-width: auto; + } + @include media-breakpoint(sm) { + max-width: 1200px; + } +} diff --git a/ui-kit/src/sass/components/_Row.scss b/ui-kit/src/sass/components/_Row.scss index b47b26af..f6468910 100644 --- a/ui-kit/src/sass/components/_Row.scss +++ b/ui-kit/src/sass/components/_Row.scss @@ -16,8 +16,9 @@ .lubycon-grid-row { display: flex; - width: 100%; margin: #{-$gutter / 2}; + flex-wrap: wrap; + box-sizing: border-box; @include direction(row); @include direction(column); diff --git a/ui-kit/src/sass/components/_index.scss b/ui-kit/src/sass/components/_index.scss index f9a31c70..a58fd748 100644 --- a/ui-kit/src/sass/components/_index.scss +++ b/ui-kit/src/sass/components/_index.scss @@ -1,3 +1,4 @@ +@import './Alert'; @import './Button'; @import './Text'; @import './Radio'; @@ -12,3 +13,4 @@ @import './Tabs'; @import './Card'; @import './Snackbar'; +@import './Container'; diff --git a/ui-kit/src/sass/utils/_breakpoints.scss b/ui-kit/src/sass/utils/_breakpoints.scss index 00fcd4cc..63cec025 100644 --- a/ui-kit/src/sass/utils/_breakpoints.scss +++ b/ui-kit/src/sass/utils/_breakpoints.scss @@ -7,7 +7,7 @@ $breakpoints: ( ) !default; @mixin media-breakpoint($size) { - @media (min-width: $size) { + @media (min-width: map-get($breakpoints, $size)) { @content; } } diff --git a/ui-kit/src/sass/utils/_colors.scss b/ui-kit/src/sass/utils/_colors.scss index 5ba2db62..875f92a2 100644 --- a/ui-kit/src/sass/utils/_colors.scss +++ b/ui-kit/src/sass/utils/_colors.scss @@ -1,24 +1,17 @@ $colors: ( - // Positive + 'green40': #dff6e7, 'green50': #13bc4c, - 'green40': #78cf81, - 'green60': #0f933c, - // Informative + 'green60': #00a438, 'blue50': #135ce9, - 'blue40': #87adf5, + 'blue40': #e6effe, 'blue60': #013cad, - // Negative 'red50': #cb121c, - 'red40': #f29ca1, + 'red40': #fae7e8, 'red60': #9b0b13, - // Notice - 'yellow50': #f0cb08, - 'yellow40': #f9e681, + 'yellow50': #f0ca08, + 'yellow40': #fdf5ce, 'yellow60': #aa8f00, - /* - Gray Scale - 100-10 (단위 10) - */ 'gray100': #1b1b1c, + 'gray100': #1b1b1c, 'gray90': #2a2a2c, 'gray80': #4c4d53, 'gray70': #76777d, @@ -28,9 +21,8 @@ $colors: ( 'gray30': #e3e4e5, 'gray20': #f3f4f5, 'gray10': #fcfcfd, - // Mono Tone 'white': #ffffff, - 'black': #000000 + 'black': #000000, ); @mixin color($name, $value) { diff --git a/ui-kit/src/stories/Alert.stories.tsx b/ui-kit/src/stories/Alert.stories.tsx new file mode 100644 index 00000000..061b3d7b --- /dev/null +++ b/ui-kit/src/stories/Alert.stories.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import Alert from 'components/Alert'; +import { Meta } from '@storybook/react/types-6-0'; +import { Column, Row } from 'src/components'; +import { SemanticColor } from 'src/constants/colors'; + +export default { + title: 'Lubycon UI Kit/Alert', +} as Meta; + +const alerts: Array<{ type: SemanticColor; title: string }> = [ + { + type: 'negative', + title: '오류', + }, + { + type: 'notice', + title: '경고', + }, + { + type: 'informative', + title: '정보', + }, + { + type: 'positive', + title: '완료', + }, +]; + +export const Default = () => { + return ( + <> + + {alerts.map(({ type, title }) => ( + + + 서브 타이틀을 넣어주세요 + + {title} 메세지를 넣어주세요 + + ))} + + + ); +}; diff --git a/ui-kit/src/stories/Colors.stories.tsx b/ui-kit/src/stories/Colors.stories.tsx index d4640d6e..7a69e60f 100644 --- a/ui-kit/src/stories/Colors.stories.tsx +++ b/ui-kit/src/stories/Colors.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Meta } from '@storybook/react/types-6-0'; import Text from 'components/Text'; -import { colors, ColorProperty, SemanticColorName } from '../constants/colors'; +import { colors, ColorProperty, SemanticColor } from '../constants/colors'; export default { title: 'Lubycon UI Kit/Colors', @@ -21,7 +21,7 @@ const grayScaleNames = [ ] as const; type SemanticColorMap = { - [key in SemanticColorName]: Array; + [key in SemanticColor]: Array; }; const semanticColors: SemanticColorMap = { @@ -31,7 +31,7 @@ const semanticColors: SemanticColorMap = { notice: ['yellow50', 'yellow40', 'yellow60'], }; -const semanticColorNames = Object.keys(semanticColors) as Array; +const semanticColorNames = Object.keys(semanticColors) as Array; type IndexMap = { [key: number]: 'a' | 'b' | 'c'; diff --git a/ui-kit/src/stories/Grid.stories.tsx b/ui-kit/src/stories/Grid.stories.tsx index e899aec6..ca3c3a1f 100644 --- a/ui-kit/src/stories/Grid.stories.tsx +++ b/ui-kit/src/stories/Grid.stories.tsx @@ -21,9 +21,9 @@ const columnStyle: CSSProperties = { }; export const Default = () => ( - + {columns.map((column) => ( - + Column{column} @@ -32,8 +32,22 @@ export const Default = () => ( ); +export const Stretched = () => ( + + {columns + .filter((v) => v % 2 === 0) + .map((column) => ( + + + Column{column} + + + ))} + +); + export const Direction = () => ( - + {columns.map((column) => ( @@ -45,23 +59,41 @@ export const Direction = () => ( ); export const Responsive = () => ( - + - lg=8 md=4, xs=2 + + lg=8 md=4, xs=2 + + + + + auto + - auto - lg=1, md=5, xs=8 + + lg=1, md=5, xs=8 + ); export const VariableWidth = () => ( - + - width: 40px + + width: 40px + + + + + Column + + + + + Column + - Column - Column );