-
Notifications
You must be signed in to change notification settings - Fork 2
[Feature] 지도 핀마커 오버레이 UI 컴포넌트 구현 #38
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
Conversation
- PinMarkerPendingIcon (보라색, 기록 완료 상태) - PinMarkerCompletedIcon (파란색, 기록 대기 상태) - 각 아이콘의 Storybook 스토리 추가
- Storybook 파일 lint 제외 설정 추가 - RefreshIcon 스토리 void expression 수정 - ErrorFallback 타입 안전성 개선
- Coordinates, PinVariant, PinMarkerData 타입 정의 - shared/types/index.ts에 export 추가
- PinMarkerPendingIcon과 PinMarkerCompletedIcon의 SVG 내용이 뒤바뀌어 있었음 - 각 아이콘 파일에 올바른 SVG 내용으로 수정
- variant 기반 핀마커 컴포넌트 (current/record) - 파란 핀: 기본 상태에서 pulse + glow 애니메이션 지속 - 보라 핀: hover 시 미세 반응, 선택 시 스윕 효과 - 선택 상태: 위로 lift 애니메이션 및 그림자 효과 - 접근성 속성 지원 (role, aria-label, aria-pressed)
- Interactive, States, Accessibility 스토리 구현 - 현재 위치/기록 완료 핀의 다양한 상태 시연
- 파란 핀 기본/선택 상태 애니메이션 분리 - 기본 상태 pulse 강도 감소 (scale 1.02) - 선택 상태 pulse 강도 증가 (scale 1.08) - 보라 핀 선택 시 scale up 효과 추가 (scale 1.06)
- PinMarkerPendingIcon의 + 표시를 그룹화하여 독립 제어 가능하도록 변경 - 선택 상태에서 + 표시가 pulse 애니메이션으로 커졌다 작아지는 효과 추가
- 불필요한 스토리 제거 (Current, Record, Matrix) - InteractiveDemo를 render 함수 내부로 이동 - AccessibilityNotes에서 키보드 관련 참고사항 제거
| ...props | ||
| }: IconProps) { | ||
| return ( | ||
| <svg |
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.
이런 svg 설정을 svgr 같은 것으로 처리하지 않는 이유가 궁금해요!!
Vite 에서 지원해주는 vite-plugin-svgr 이런걸 쓰면 최적화도 자동으로 해준다고 본 거 같아서요!!
(번들 크기 최소화, tree-shaking 등)
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.
고민을 해보긴 했는데,
개발 편의와 운영 측면에서 svg를 컴포넌트화하는게 더 편해서 이쪽으로 진행하고 있어요!
src아래 자산은 어차피 번들링 대상이라 svgr을 도입한다고 해서 성능/최적화가 결정적으로 달라진다고 보진 않았고,- 현재 단계에서는 관리할 SVG 파일이 많지 않고 점진적으로 늘어나는 구조라, 초기 셋업(플러그인/규칙/컨벤션) 비용을 먼저 지는 것보다 필요해졌을 때 도입하는 편이 더 합리적이라고 판단했습니다!
특히 제가 아직 svgr에 익숙하지 못한 탓도 있겠지만,
관리할 아이콘들이 상태별로 내부 요소(ex. 색상 변경)를 제어하는 경우가 많은데.
svgr 같은 경우는 currentColor 규칙에 맞춰 fill/stroke를 정리하거나 변환 옵션을 관리해서 파일을 붙여야,
<PinIcon
className={cn(
'w-6 h-6',
isSelected && 'text-blue-600'
)}
data-selected={isSelected}
/>이런 식의 제어가 가능해지는데.
특정 path만 class를 붙이고 싶어지면 또 다시 svgr 결과물을 내부적으로 편집하고...
요런게 직접 svg를 컴포넌트화했을 때보다 관리가 불편하다고 생각합니다!
return (
<svg className={iconClass}>
<g className={isSelected ? 'icon-plus-selected' : 'icon-plus'}>
<g className="icon-body" />
</svg>
);이게 더 보기 편한 느낌이라, 현재는 이렇게 진행하고 있습니다!
추후 아이콘 에셋이 대량으로 늘면 svgr을 도입해도 좋을 것 같아요.
숙련도 부족 이슈 ㅠㅠ
|
|
||
| if (isCurrent && !isSelected) classes.push('pin-blue-idle'); | ||
|
|
||
| if (isSelected) | ||
| classes.push(isCurrent ? 'pin-blue-selected' : 'pin-purple-selected'); | ||
|
|
||
| // 보라색 핀 hover 시 살짝 반응 (데스크톱 전용) | ||
| if (isRecord && !isSelected && isHovered) classes.push('pin-purple-hover'); |
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.
이 조건문들이 핀의 상태(Idle, Selected, Hover)를 결정하기 위한 로직 같은데 isCurrent && !isSelected 처럼 조건이 나열되어 있다 보니 한눈에 의도를 파악하기가 조금 어려운 거 같아요 😅
의미를 담은 변수 또는 함수 추출해보는 건 어떨까요?
스타일을 적용하는 로직(코드)가 가독성도 좋아지고 문서처럼 보일 수도 있을거 같아요!!
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.
const isBlueIdle = isCurrent && !isSelected;
const isBlueSelected = isCurrent && isSelected;
const isPurpleSelected = isRecord && isSelected;
const isPurpleHover = isRecord && !isSelected && isHovered;
if (isBlueIdle) classes.push('pin-blue-idle');
if (isBlueSelected) classes.push('pin-blue-selected');
if (isPurpleSelected) classes.push('pin-purple-selected');
if (isPurpleHover) classes.push('pin-purple-hover');이런 식으로 말씀이시죠?
저도 고민했던 포인트였는데,
요게 변수 이름 정하기가 어려워서 ㅠㅠ (변수 이름이 길면 읽기 어려울거같은데 뭔가 와닿는게 없는 상태)
고민하다가 일단 유지시키는 쪽으로 PR을 날렸는데,
변수 이름을 조금 더 고민해보고 적용해보겠습니다!
|
같은 좌표의 여러 핀이 있을 때(current, record) 렌더링 순서에 따라 뒤의 핀이 앞의 핀을 가릴 수 있을 거 같아요!! 이 부분은 Map에 실제 핀을 적용할 때 처리되는 것이겠죠?!? |
|
좋은 의견 감사합니다!
말씀해주신 것처럼, 이 부분은 실제 Map SDK를 도입하면서
구체적인 동작을 함께 정리해보겠습니다! 이번 PR에서는 UI 컴포넌트 구현에 집중하고, |
📌 관련 이슈
Closed #34 , #36
✅ PR 체크리스트(최소요구조건)
✨ 작업 개요
🧹 작업 상세 내용
PinMarker UI 컴포넌트 구현
current/record상태에 따른 핀 타입 분리핀 상태별 아이콘 및 모션 차별화
Storybook 스토리 추가
린트 및 설정 관련 이슈 해결
📸 스크린샷 (선택)
🔍 고민 지점
[ transform 속성이 의도대로 적용되지 않는 문제 ]
문제점
핀 선택 상태에서
scale,translate등의 transform 효과를 단계적으로 적용하고 싶었으나,CSS transform 특성상 동일 요소에 transform은 하나의 값만 적용되기 때문에
상태별로 transform을 덮어쓰는 구조가 되어 의도한 조합이 어려웠습니다.
특히 SVG 내부 요소와 상위 컨테이너에 transform이 혼재되면서
기준점(origin)이 어긋나거나, 일부 transform이 무시되는 문제가 발생했습니다.
해결 과정
transform-origin을 명시적으로 지정scale / translate / opacity 효과를 조합하는 방식으로 구조 변경
결과적으로,
“하나의 transform을 어떻게 덮어쓸 것인가”보다
**“어떤 상태 조합을 클래스 레벨에서 표현할 것인가”**에 초점을 맞추는 방향으로 설계를 변경했습니다.
Note
CSS
transform은 하나의 요소에 대해 단일 속성으로 취급되기 때문에여러 클래스에서
transform을 각각 정의하면 마지막 선언만 적용됩니다.예를 들어, 아래와 같은 경우 의도한 동작이 나오지 않습니다.
→ 결과적으로
scale(1.1)만 적용되고,translateY는 무시됩니다.이를 피하기 위해 본 구현에서는
상태별로 transform을 조합한 클래스를 명시적으로 분리하는 방식을 선택했습니다.
이 구조를 통해
[ 두 가지 핀을 어떻게 다른 ‘존재감’으로 보여줄 것인가 ]
문제점
파란 핀과 보라 핀은 역할이 다르기 때문에
동일한 애니메이션과 시각적 강조를 주는 것이 오히려 UX를 해칠 수 있다고 판단했습니다.
파란 핀:
→ 사용자의 시선을 적극적으로 끌 필요가 있음
보라 핀:
→ 과도한 spotlight는 불필요
해결 과정
결과적으로,
사용자에게는 자연스럽게 우선순위가 전달되는 인터랙션을 목표로 했습니다.
💬 기타 참고 사항
실제 지도 SDK 연동 이후에도 재사용 가능하도록 설계했습니다.
핀 상태 확장이 가능하도록 타입 구조를 열어두었습니다.
Note
API 명세 협의가 아직 완료되지 않아,
PinMarkerData의 필드 구성과 값은 UI 구현을 위한 임시 값으로 정의되어 있습니다.추후 API 스펙 확정 시 변경될 예정입니다.