Skip to content

[Setting/#143] 공통 UI 컴포넌트 생성#144

Merged
dew102938 merged 4 commits into
developfrom
setting/#143
May 16, 2026
Merged

[Setting/#143] 공통 UI 컴포넌트 생성#144
dew102938 merged 4 commits into
developfrom
setting/#143

Conversation

@dew102938
Copy link
Copy Markdown
Contributor

@dew102938 dew102938 commented May 15, 2026

🔢 관련 이슈 링크

📌 변경사항PR

  • ✨Feature: 새로운 기능 추가
  • 🐞Bugfix: 버그/오류 수정
  • 📃Docs: 문서 수정(README 등)
  • 🔨Refactor: 코드 리팩토링 (기능 변경 없음)
  • 🧪Test: 테스트 코드 추가/수정
  • 🎨UI/UX: 디자인 및 사용성 수정
  • ⚙️Setting: 기본 세팅 작업

💻 작업내용

  • 버튼 컴포넌트
    glass(투명배경), solid(검정배경) 두 가지 스타일로 나눠 variant로 관리하도록 구현
  • 검색창 컴포넌트
  • 인풋 컴포넌트
    라벨 포함
  • 식당 카드 컴포넌트

🪧 미완성 작업

N/A

🤔 논의 사항 및 참고 사항

프로토타입 디자인을 참고하여 색상 팔레트(gold-1, black-1 등)으로 임의 매칭하여 구현했습니다.
ui 확인은 아래 영상을 통해 확인해주세요

default.mp4

✅ 체크리스트

  • 브랜치는 잘 맞게 올렸는지
  • 관련 이슈를 맞게 연결했는지
  • 로컬에서 정상 동작을 확있했는지
  • 충돌은 없는지
  • 불필요한 console.log 제거했는지

Summary by CodeRabbit

  • New Features
    • 재사용 가능한 UI 컴포넌트 추가: 버튼(variant/size 지원), 입력 필드, 검색 입력 필드, 레스토랑 카드(이미지·평점·정보 표시)
    • 테마 스타일시트가 도입되어 Tailwind 기반 전체 디자인 일관성 및 스타일 커스터마이징이 향상되었습니다

Review Change Stack

@dew102938 dew102938 requested a review from jjjsun May 15, 2026 15:34
@dew102938 dew102938 self-assigned this May 15, 2026
@dew102938 dew102938 added the ⚙️ Setting 기본 세팅 작업 label May 15, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
eatsfine Ready Ready Preview, Comment May 16, 2026 1:34pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@dew102938 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 50 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 84e06b8d-91b9-433a-a126-ea82319a7d94

📥 Commits

Reviewing files that changed from the base of the PR and between b346efc and a117a5d.

📒 Files selected for processing (1)
  • src/components/common/Card.tsx
📝 Walkthrough

Walkthrough

PR #144은 Tailwind/CVA 기반 공통 UI 컴포넌트 네 가지(BaseButton, BaseInput, SearchInput, RestaurantCard)를 forwardRef 패턴으로 추가하고, 테마 CSS(src/styles/theme.css)를 앱 진입점에 임포트합니다.

Changes

Common UI Component Library

Layer / File(s) Summary
Tailwind CSS 테마 인프라
src/styles/theme.css, src/main.tsx
@import "tailwindcss";를 theme.css에 추가하고 src/main.tsx에서 ./styles/theme.css를 임포트하여 Tailwind 로딩을 연결합니다.
BaseButton: variant·size 기반 스타일링
src/components/common/Button.tsx
CVA(cva)로 buttonVariants를 정의(variant: glass
BaseInput: 라벨·래퍼 커스터마이징
src/components/common/Input.tsx
BaseInputlabel, wrapperClassName, labelClassName 옵션을 지원하며 기본 type="text"로 동작하고 forwardRef로 input ref를 노출합니다.
SearchInput: 검색 아이콘 통합
src/components/common/SearchInput.tsx
검색 SVG를 포함한 래퍼와 입력을 렌더링하고 wrapperClassName, iconClassName, className을 각각 적용하는 SearchInputforwardRef로 추가합니다.
RestaurantCard: 레스토랑 정보 카드
src/components/common/Card.tsx
이미지(호버 확대), 오버레이, 별점 표시, 카테고리/이름/위치 텍스트, 하단 'View Details' 액션을 포함한 RestaurantCardforwardRef 기반 버튼 컴포넌트로 구현합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Eatsfine/FE#142: src/styles/theme.css의 Tailwind 관련 변경과 직접 연관됩니다.
  • Eatsfine/FE#33: 전역 CSS/Tailwind 진입점 재구성 작업과 관련 있습니다.

Suggested labels

🎨 Design

Suggested reviewers

  • jjjsun
  • yooseolhee

🎨 공용 UI를 짓는 날,
Tailwind 선율에 맞춰
버튼·입력·검색·카드가
ref를 건네고 클래스를 합쳐
화면 위에 조용히 웃네 ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경사항의 핵심을 명확히 전달합니다. 공통 UI 컴포넌트 생성이라는 주요 변경을 잘 요약했습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르며 이슈 링크, 변경사항 체크, 작업 내용, 참고사항이 모두 기재되어 있습니다.
Linked Issues check ✅ Passed PR이 이슈 #143의 모든 요구사항을 충족합니다. 버튼, 검색창, 인풋, 카드 컴포넌트가 모두 components/common에 구현되었습니다.
Out of Scope Changes check ✅ Passed PR의 모든 변경사항이 이슈 #143의 범위 내입니다. 공통 컴포넌트 생성 및 테마 CSS 설정만 포함되어 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch setting/#143

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
src/components/common/Card.tsx (1)

1-3: ⚡ Quick win

lint 경고(임포트 정렬) 한 번 정리해두면 좋아요.

정적 분석 경고대로 import 정렬 autofix를 적용해 두면 이후 CI 노이즈를 줄일 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/Card.tsx` around lines 1 - 3, Import sorting in
src/components/common/Card.tsx is triggering a lint warning; reorder the imports
(external packages first, then type imports, then local modules) and run the
project's autofix to remove CI noise. Specifically, update the import block that
references React/forwardRef and clsx/ClassValue and twMerge so they follow the
project's import-order rule (or run eslint --fix / npm run lint:fix) to
automatically sort and group these imports. Ensure you save the file and commit
the autofixed changes.
src/components/common/SearchInput.tsx (1)

14-47: ⚡ Quick win

React 19에서 ref를 prop으로 직접 받을 수 있어요 (선택사항)

프로젝트가 React 19.2를 사용하고 있는데, 이제 ref가 일반 prop이 되어서 forwardRef를 꼭 써야 하지는 않습니다. 현재 코드는 완벽하게 동작하지만, 더 간단하게 리팩토링할 수 있어요.

✨ forwardRef 제거 예시
export const SearchInput = ({ 
  className, 
  wrapperClassName, 
  iconClassName, 
  ref,
  ...props 
}: SearchInputProps & { ref?: React.Ref<HTMLInputElement> }) => {
  return (
    <div className={cn("group relative w-full", wrapperClassName)}>
      <input
        ref={ref}
        type="search"
        className={cn(
          "w-full bg-white-1/5 border-b-2 border-white-1/20 text-white-1 px-4 py-4 pl-12 focus:outline-none focus:border-gold-1 focus:bg-white-1/10 transition-all duration-300 font-light placeholder:text-white-1/40",
          className,
        )}
        {...props}
      />
      <svg
        className={cn(
          "absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-white-1/50 transition-colors duration-300 group-focus-within:text-gold-1",
          iconClassName,
        )}
        fill="none"
        viewBox="0 0 24 24"
        stroke="currentColor"
        aria-hidden="true"
      >
        <path
          strokeLinecap="round"
          strokeLinejoin="round"
          strokeWidth={1.5}
          d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
        />
      </svg>
    </div>
  );
};

SearchInput.displayName = "SearchInput";

현재 구현도 잘 동작하지만, 원하면 이렇게 간단히 개선할 수 있습니다. 접근성도 이미 잘 처리되어 있네요! (aria-hidden 👍)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/SearchInput.tsx` around lines 14 - 47, The component
currently uses forwardRef (export const SearchInput = forwardRef...) but with
React 19 you can accept ref as a normal prop; refactor SearchInput to be a plain
functional component that takes ref?: React.Ref<HTMLInputElement> on its props
(SearchInputProps & { ref?: React.Ref<HTMLInputElement> }), remove forwardRef
usage, keep assigning ref to the <input> element, set SearchInput.displayName =
"SearchInput", and optionally change the input type to "search" if desired;
ensure the prop names (className, wrapperClassName, iconClassName) and the SVG
markup remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/common/Button.tsx`:
- Around line 37-40: BaseButton currently renders a <button> without a default
type which makes it default to "submit" inside forms; update the BaseButton
render to use a safe default type="button" while still allowing consumers to
override via props (ensure ButtonProps/types include the native button type if
not already). Locate the forwardRef component named BaseButton and modify the
props handling so the rendered button receives a default type of "button" unless
an explicit type prop is provided (keeping existing usage of cn and
buttonVariants intact).

In `@src/components/common/Card.tsx`:
- Around line 29-33: The decorative SVG in Card.tsx (the <svg> element used for
the star icon) should be hidden from assistive tech: update the SVG in the
rating block (and the similar SVG at the other occurrence between lines 49-61)
to include aria-hidden="true" and focusable="false" and ensure no meaningful
content is duplicated only in the decorative element; keep visible/readable
content (e.g., the rating value rendered by the span with className
"text-white-1 text-xs font-light tracking-wider" / the prop rating) as the
accessible representation.
- Line 20: Card.tsx currently renders an interactive container as a plain div
(the element with "ref={ref} className={cn(\"group cursor-pointer\", className)}
{...props}") which breaks keyboard accessibility; update this root element to
either a semantic interactive element (preferably a <button> or <a> if it
navigates) keeping the existing ref and props, or if you must keep a div add
role="button", tabIndex={0} and implement an onKeyDown handler that invokes the
same activation logic as onClick for Enter and Space, and ensure ARIA attributes
(aria-pressed/aria-label etc.) are forwarded from props so keyboard and
screen-reader users can operate the Card component.

In `@src/components/common/Input.tsx`:
- Around line 19-31: The <label> lacks an htmlFor/id connection to the <input>,
breaking screen-reader and click-to-focus behavior; update the Input component
to accept an optional id prop (or generate a stable one using React's useId
inside the component) and ensure the <label> uses htmlFor={id} while the <input>
receives id={id}; reference the label element that currently uses
labelClassName, the input element using ref and props.type, and update the
component props/type declarations to include id so callers can override it.

In `@src/components/common/SearchInput.tsx`:
- Around line 18-26: The SearchInput component is missing accessibility
attributes and should use a semantic search input: update the props interface
(SearchInputProps) to include an optional "aria-label"?: string and ensure the
rendered <input> (the element using ref and {...props}) uses type="search"
instead of "text" and passes through the aria-label from props (or supply a
sensible default like "Search" only if no label is provided). Make sure the
input still spreads {...props} so any consumer-provided aria attributes are
preserved and adjust any consuming code/tests if they relied on type="text".
- Around line 5-7: Remove the locally defined cn function in SearchInput.tsx
(the function named cn that wraps twMerge and clsx) and replace it with an
import of the shared cn utility from the common utils module (use the existing
cn exported from the shared utils file), then update any references in
SearchInput.tsx to use the imported cn; ensure the import uses the same named
export (cn) so no other code changes are required.

---

Nitpick comments:
In `@src/components/common/Card.tsx`:
- Around line 1-3: Import sorting in src/components/common/Card.tsx is
triggering a lint warning; reorder the imports (external packages first, then
type imports, then local modules) and run the project's autofix to remove CI
noise. Specifically, update the import block that references React/forwardRef
and clsx/ClassValue and twMerge so they follow the project's import-order rule
(or run eslint --fix / npm run lint:fix) to automatically sort and group these
imports. Ensure you save the file and commit the autofixed changes.

In `@src/components/common/SearchInput.tsx`:
- Around line 14-47: The component currently uses forwardRef (export const
SearchInput = forwardRef...) but with React 19 you can accept ref as a normal
prop; refactor SearchInput to be a plain functional component that takes ref?:
React.Ref<HTMLInputElement> on its props (SearchInputProps & { ref?:
React.Ref<HTMLInputElement> }), remove forwardRef usage, keep assigning ref to
the <input> element, set SearchInput.displayName = "SearchInput", and optionally
change the input type to "search" if desired; ensure the prop names (className,
wrapperClassName, iconClassName) and the SVG markup remain unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 91e6a7aa-d787-4b75-b620-59549867e618

📥 Commits

Reviewing files that changed from the base of the PR and between ebfb28b and f9d74bc.

📒 Files selected for processing (6)
  • src/components/common/Button.tsx
  • src/components/common/Card.tsx
  • src/components/common/Input.tsx
  • src/components/common/SearchInput.tsx
  • src/main.tsx
  • src/styles/theme.css

Comment thread src/components/common/Button.tsx Outdated
Comment thread src/components/common/Card.tsx Outdated
Comment thread src/components/common/Card.tsx Outdated
Comment thread src/components/common/Input.tsx
Comment thread src/components/common/SearchInput.tsx Outdated
Comment thread src/components/common/SearchInput.tsx
@jjjsun
Copy link
Copy Markdown
Contributor

jjjsun commented May 16, 2026

디자인 엄청 고급스럽게 잘 나왔네요!! 좋습니다!! 확인했어요~~

@jjjsun
Copy link
Copy Markdown
Contributor

jjjsun commented May 16, 2026

import 문 정렬문제만 해결해주시면 될것같습니다!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/common/Card.tsx (1)

25-28: ⚡ Quick win

이미지에 loading="lazy"를 추가하면 성능이 개선돼요.

페이지에 여러 개의 레스토랑 카드가 있을 때, 화면에 보이지 않는 이미지까지 한꺼번에 로드하면 초기 로딩이 느려질 수 있어요. loading="lazy"를 추가하면 스크롤할 때만 이미지를 불러와서 성능이 좋아집니다.

♻️ 수정 제안
           <img
             src={image}
             alt={name}
+            loading="lazy"
             className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
           />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/Card.tsx` around lines 25 - 28, The img in Card.tsx
(the <img> element rendering src={image} alt={name} with className="w-full
h-full object-cover...") should use native lazy loading to improve performance
for lists of cards; add the attribute loading="lazy" to that <img> element so
offscreen images are deferred until scrolled into view.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/common/Card.tsx`:
- Around line 16-23: The button in the Card component is missing an explicit
type which can cause accidental form submissions when this component is used
inside a form; update the button element in src/components/common/Card.tsx (the
JSX element that uses ref, className, and {...props}) to include type="button"
so it never acts as a submit button by default.

---

Nitpick comments:
In `@src/components/common/Card.tsx`:
- Around line 25-28: The img in Card.tsx (the <img> element rendering
src={image} alt={name} with className="w-full h-full object-cover...") should
use native lazy loading to improve performance for lists of cards; add the
attribute loading="lazy" to that <img> element so offscreen images are deferred
until scrolled into view.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 40795854-d1f8-431c-8128-fbec3500a3e4

📥 Commits

Reviewing files that changed from the base of the PR and between f9d74bc and b346efc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml and included by none
📒 Files selected for processing (5)
  • src/components/common/Button.tsx
  • src/components/common/Card.tsx
  • src/components/common/Input.tsx
  • src/components/common/SearchInput.tsx
  • src/main.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/main.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/common/Button.tsx
  • src/components/common/Input.tsx

Comment thread src/components/common/Card.tsx
@dew102938 dew102938 merged commit ac52c9d into develop May 16, 2026
4 checks passed
@dew102938 dew102938 deleted the setting/#143 branch May 16, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚙️ Setting 기본 세팅 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

⚙️ [Setting] 공통 UI 컴포넌트 생성 (버튼, 검색창, 인풋, 카드)

2 participants