-
Notifications
You must be signed in to change notification settings - Fork 2
[refactor] 퍼널 공통 헤더 v2 전환 및 InteriorStyle 디자인 리뉴얼 #511
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
Changes from 5 commits
0bed44d
27ba0f4
777985a
95e9cbe
12b7325
40f5505
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 |
|---|---|---|
| @@ -1,27 +1,32 @@ | ||
| import { style } from '@vanilla-extract/css'; | ||
|
|
||
| import { zIndex } from '@styles/tokens/zIndex'; | ||
| import { unitVars } from '@styles/tokensV2/unit.css'; | ||
|
|
||
| export const container = style({ | ||
| position: 'relative', | ||
| display: 'flex', | ||
| flex: 1, | ||
| flexDirection: 'column', | ||
| alignItems: 'center', | ||
| gap: unitVars.unit.gapPadding['800'], | ||
| marginBottom: '9.6rem', | ||
| padding: unitVars.unit.gapPadding['500'], | ||
| width: '100%', | ||
| }); | ||
|
|
||
| export const headingWrapper = style({ | ||
| display: 'flex', | ||
| width: '100%', | ||
| }); | ||
|
|
||
| // 데스크탑·모바일 모두에서 44rem 가상 프레임의 우하단에 2rem씩 띄운 floating 버튼 | ||
| // - 모바일(뷰포트 ≤ 44rem): right: 2rem — 뷰포트 우측에서 2rem | ||
| // - 데스크탑(뷰포트 > 44rem): right: calc((100vw - 44rem) / 2 + 2rem) — 프레임 우측에서 2rem 안쪽 | ||
| // - max()로 두 경우를 한 식에 통합 | ||
| export const buttonWrapper = style({ | ||
| position: 'fixed', | ||
| zIndex: zIndex.button, | ||
| right: 0, | ||
| bottom: '2rem', // CtaButton 최대 너비 설정 | ||
| left: 0, | ||
| display: 'flex', | ||
| justifyContent: 'center', | ||
| margin: '0 auto', | ||
| padding: '0 2rem 0 2rem', | ||
| width: '100%', | ||
| maxWidth: '44rem', | ||
| right: 'max(2rem, calc((100vw - 44rem) / 2 + 2rem))', | ||
| bottom: '2rem', | ||
|
jstar000 marked this conversation as resolved.
|
||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { style } from '@vanilla-extract/css'; | ||
| import { recipe } from '@vanilla-extract/recipes'; | ||
|
|
||
| import { colorVars } from '@styles/tokensV2/color.css'; | ||
| import { fontVars } from '@styles/tokensV2/font.css'; | ||
| import { unitVars } from '@styles/tokensV2/unit.css'; | ||
|
|
||
| // 카드 컨테이너 | ||
| // - default: 1px secondary 테두리, 둥근 사각형 | ||
| // - selected: 1.5px strong 테두리 | ||
| // - disabled: opacity 0.5 | ||
| export const card = recipe({ | ||
| base: { | ||
| aspectRatio: '164 / 240', | ||
| position: 'relative', | ||
| transition: 'transform 120ms ease', | ||
| border: `1px solid ${colorVars.color.border.secondary}`, | ||
| borderRadius: unitVars.unit.radius['600'], | ||
| backgroundColor: 'transparent', | ||
| cursor: 'pointer', | ||
| width: '100%', | ||
| overflow: 'hidden', | ||
| selectors: { | ||
| '&:active': { | ||
| transform: 'scale(0.95)', | ||
| }, | ||
| }, | ||
| }, | ||
| variants: { | ||
| state: { | ||
| default: {}, | ||
| selected: { | ||
| border: `1.5px solid ${colorVars.color.border.strong}`, | ||
| }, | ||
| disabled: { | ||
| opacity: 0.5, | ||
| cursor: 'not-allowed', | ||
| selectors: { | ||
| '&:active': { | ||
| transform: 'none', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| defaultVariants: { | ||
| state: 'default', | ||
| }, | ||
| }); | ||
|
|
||
| export const image = style({ | ||
| display: 'block', | ||
| objectFit: 'cover', | ||
| objectPosition: 'center', | ||
| width: '100%', | ||
| height: '100%', | ||
| userSelect: 'none', | ||
| }); | ||
|
|
||
| // 체크박스 — 우상단에 패딩 16px 영역 안에 위치 | ||
| export const checkbox = recipe({ | ||
| base: { | ||
| position: 'absolute', | ||
| top: 0, | ||
| right: 0, | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| border: 'none', | ||
| background: 'transparent', | ||
| pointerEvents: 'none', | ||
| padding: unitVars.unit.gapPadding['400'], | ||
| }, | ||
| variants: { | ||
| state: { | ||
| // default: 흰 stroke 빈 동그라미 20×20 | ||
| default: {}, | ||
| // selected: 다크 배경 24×24, 흰 숫자 | ||
| selected: {}, | ||
| }, | ||
| }, | ||
| }); | ||
|
Comment on lines
+76
to
+84
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. 🧹 Nitpick | 🔵 Trivial 주석과 실제 구현 불일치 + 빈 variants 정리 필요 Line 78의 주석에 "20×20"이라고 되어 있지만, 또한 💡 제안된 수정 export const checkbox = recipe({
base: {
position: 'absolute',
top: 0,
right: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: 'none',
background: 'transparent',
pointerEvents: 'none',
padding: unitVars.unit.gapPadding['400'],
},
variants: {
state: {
- // default: 흰 stroke 빈 동그라미 20×20
+ // 스타일 차이는 circle 레시피에서 처리
default: {},
- // selected: 다크 배경 24×24, 흰 숫자
selected: {},
},
},
});🤖 Prompt for AI Agents |
||
|
|
||
| // 체크박스 안의 동그라미 | ||
| export const circle = recipe({ | ||
| base: { | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| transition: | ||
| 'width 120ms ease, height 120ms ease, background-color 120ms ease', | ||
| borderRadius: unitVars.unit.radius.full, | ||
| }, | ||
| variants: { | ||
| state: { | ||
| default: { | ||
| border: `1px solid ${colorVars.color.border.secondary}`, | ||
| backgroundColor: `${colorVars.color.fill.inverseSecondary}`, | ||
| width: '2.4rem', | ||
| height: '2.4rem', | ||
| }, | ||
| selected: { | ||
| border: 'none', | ||
| backgroundColor: colorVars.color.fill.strong, | ||
| width: '2.4rem', | ||
| height: '2.4rem', | ||
| color: colorVars.color.text.inverse, | ||
| ...fontVars.font.body_m_14, | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import * as styles from './MoodboardCard.css'; | ||
|
|
||
| interface MoodboardCardProps extends React.ComponentProps<'div'> { | ||
| src: string; | ||
| alt: string; | ||
| selectOrder?: number; | ||
| disabled?: boolean; | ||
| onClick?: () => void; | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| const MoodboardCard = ({ | ||
| src, | ||
| alt, | ||
| selectOrder = 0, | ||
| disabled = false, | ||
| onClick, | ||
| }: MoodboardCardProps) => { | ||
| const isSelected = selectOrder > 0; | ||
|
|
||
| // 상태 결정 우선순위: disabled > selected > default | ||
| // pressed 인터랙션은 CSS :active 셀렉터로 처리 (v2 컨벤션) | ||
| const visualState = disabled | ||
| ? 'default' // disabled는 별도 variant | ||
| : isSelected | ||
| ? 'selected' | ||
| : 'default'; | ||
|
|
||
| const cardState = disabled ? 'disabled' : visualState; | ||
|
|
||
| const handleClick = () => { | ||
| if (disabled) return; | ||
| onClick?.(); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className={styles.card({ state: cardState })} onClick={handleClick}> | ||
|
jstar000 marked this conversation as resolved.
Outdated
|
||
| <img src={src} alt={alt} className={styles.image} draggable={false} /> | ||
| {!disabled && ( | ||
| <div className={styles.checkbox({ state: visualState })}> | ||
| <span className={styles.circle({ state: visualState })}> | ||
| {isSelected ? selectOrder : ''} | ||
| </span> | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default MoodboardCard; | ||
Uh oh!
There was an error while loading. Please reload this page.