-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
템플릿 공개 범위 설정(visibility) 기능 구현 #787
Changes from all commits
2624021
58bb5bb
1a2b8ce
d02c9e3
ee6ab09
9ee92c2
958134e
667e00b
bde5bd0
32f9d79
dce2a9c
2e35446
c388587
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
export const CategoryDropdownContainer = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 0.5rem; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import { useState } from 'react'; | ||
|
||
import Toggle from './Toggle'; | ||
|
||
const meta: Meta<typeof Toggle> = { | ||
title: 'Toggle', | ||
component: Toggle, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof Toggle>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
options: ['private', 'public'], | ||
selectedOption: 'private', | ||
}, | ||
|
||
render: (args) => { | ||
const [selectedOption, setSelectedOption] = useState(args.selectedOption); | ||
|
||
const handleToggle = (option: string) => { | ||
setSelectedOption(option); | ||
}; | ||
|
||
return <Toggle options={args.options} selectedOption={selectedOption} switchOption={handleToggle} />; | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
import { theme } from '@/style/theme'; | ||
|
||
export const ToggleContainer = styled.div` | ||
cursor: pointer; | ||
|
||
position: relative; | ||
|
||
overflow: hidden; | ||
display: flex; | ||
|
||
max-width: 12rem; | ||
height: 2.375rem; /* Button medium size와 동일 */ | ||
|
||
background-color: ${theme.color.light.secondary_100}; | ||
border-radius: 20px; | ||
`; | ||
|
||
export const ToggleOption = styled.div<{ selected: boolean }>` | ||
z-index: 1; | ||
|
||
display: flex; | ||
flex: 1; | ||
gap: 1px; | ||
align-items: center; | ||
justify-content: center; | ||
|
||
padding: 0 1rem; | ||
|
||
color: ${({ selected }) => (selected ? theme.color.light.white : theme.color.light.secondary_500)}; | ||
|
||
transition: color 0.3s ease; | ||
`; | ||
|
||
export const ToggleSlider = styled.div<{ | ||
isRight: boolean; | ||
optionSliderColor: [string | undefined, string | undefined]; | ||
}>` | ||
position: absolute; | ||
top: 2px; | ||
left: 2px; | ||
transform: ${({ isRight }) => (isRight ? 'translateX(calc(100% - 4px))' : 'translateX(0)')}; | ||
|
||
width: 50%; | ||
height: calc(100% - 4px); | ||
|
||
background-color: ${({ isRight, optionSliderColor: [leftColor, rightColor] }) => | ||
isRight ? (rightColor ?? theme.color.light.secondary_500) : (leftColor ?? theme.color.light.secondary_500)}; | ||
border-radius: 18px; | ||
|
||
transition: | ||
transform 0.3s ease, | ||
background-color 0.3s ease; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { ReactNode } from 'react'; | ||
|
||
import * as S from './Toggle.style'; | ||
|
||
type ToggleOption<T extends string> = T; | ||
|
||
export interface ToggleProps<T extends string> { | ||
showOptions?: boolean; | ||
options: [ToggleOption<T>, ToggleOption<T>]; | ||
optionSliderColor?: [string | undefined, string | undefined]; | ||
optionAdornments?: [ReactNode, ReactNode]; | ||
selectedOption: ToggleOption<T>; | ||
switchOption: (option: ToggleOption<T>) => void; | ||
} | ||
|
||
const Toggle = <T extends string>({ | ||
showOptions = true, | ||
options, | ||
optionAdornments = [undefined, undefined], | ||
optionSliderColor = [undefined, undefined], | ||
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 값들을 undefined로 기본값을 줘야하는 이유가 뭔가요?! 혹시 이후 사용처에서 옵셔널 체이닝을 쓰지 않기 위함인가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 아래와 같이 구조분해 할당을 해서 사용하고 있는데, const [leftOptionAdornment, rightOptionAdornment] = optionAdornments; 해당 값들에 기본값을 주지 않으면 아래와 같은 에러가 납니다.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 두 props를 분리해서 쓰면 더 명확해지는 대신 props가 많아질까요? |
||
selectedOption, | ||
switchOption, | ||
}: ToggleProps<T>) => { | ||
const [leftOption, rightOption] = options; | ||
const [leftOptionAdornment, rightOptionAdornment] = optionAdornments; | ||
|
||
const handleToggle = () => { | ||
const newOption = selectedOption === leftOption ? rightOption : leftOption; | ||
|
||
switchOption(newOption); | ||
}; | ||
|
||
return ( | ||
<S.ToggleContainer onClick={handleToggle}> | ||
<S.ToggleSlider isRight={selectedOption === rightOption} optionSliderColor={optionSliderColor} /> | ||
<S.ToggleOption selected={selectedOption === leftOption}> | ||
{leftOptionAdornment ?? ''} | ||
{showOptions && leftOption} | ||
</S.ToggleOption> | ||
<S.ToggleOption selected={selectedOption === rightOption}> | ||
{showOptions && rightOption} | ||
{rightOptionAdornment ?? ''} | ||
</S.ToggleOption> | ||
</S.ToggleContainer> | ||
); | ||
}; | ||
|
||
export default Toggle; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 이렇게 처리를 했군요?! 사실 상수로 할 생각은 안해봐서 신박했습니다.
원래는
HamburgerIcon
에 Props를 필요에 따라 medium, large 이런 식으로 하려 했거든요.다만 상수로 하니까 애매한 건 MEDIUM_LARGE 같은 상수가 나와버리네요..! ㅋㅋㅋ