Skip to content

feat : 노래 검색 및 곡 선택 플로우 구현 - #58

Merged
kim3360 merged 20 commits into
developfrom
feat/29-song-search-flow
Jul 25, 2026
Merged

kim3360 merged 20 commits into
developfrom
feat/29-song-search-flow

Conversation

@kim3360

@kim3360 kim3360 commented Jul 14, 2026

Copy link
Copy Markdown
Member

변경 내용

  • SongBottom: 검색 리스트 ↔ 상세 스텝 전환 (search / detail)
  • SongDetailContent: 미리보기 웨이브폼, 트림 구간, 소개글, 태그 선택 UI 추가
  • Song 타입에 미리보기 관련 필드 확장 (previewUrl, duration, waveformPeaks 등)
  • play / pencil 아이콘 및 mock 미리보기 데이터 추가

관련 이슈

Closes #29

변경 사항

  • 새로운 기능 추가
  • 버그 수정
  • UI/UX 개선
  • 리팩토링
  • 문서 업데이트

테스트

  • 브라우저에서 정상 동작 확인
  • 기존 기능에 영향 없음 확인

스크린샷 (UI 변경시)

image

체크리스트

  • 코드가 정상적으로 동작합니다
  • 새로운 에러나 경고가 없습니다
  • 필요시 문서를 업데이트했습니다
  • 코드 포맷팅을 실행했습니다 (pnpm format)
  • ESLint 검사를 통과했습니다 (pnpm lint:fix)

코드 품질 확인
PR 제출 전에 다음 명령어를 실행하여 코드 품질을 확인해주세요:

pnpm lint:fix
pnpm format

Summary by CodeRabbit

  • 새로운 기능
    • 곡 목록에서 곡을 검색하고 상세/등록 화면으로 이동할 수 있습니다.
    • 곡 상세/등록 화면에서 커버, 아티스트, 웨이브폼 기반 트림 프리뷰와 구간(시작/끝)을 확인할 수 있습니다.
    • 곡 소개(최대 100자), 태그(최대 4개), 피드 공개 토글을 설정할 수 있습니다.
    • 곡 선택 시 시트가 반 스냅에서 전체 화면으로 확장됩니다.
  • 개선 사항
    • 곡 카드에 아티스트 이미지와 클릭 가능한 표시(커서) 및 대체 텍스트가 추가되었습니다.
    • 핀 카드 클릭 구조/표시를 정리했습니다.
    • 태그 기본 패딩이 조정되었습니다.

@kim3360 kim3360 self-assigned this Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

곡 목업 데이터와 프리뷰 유틸을 추가하고, 곡 목록·상세 페이지 및 라우트를 구현했습니다. 곡 선택 BottomSheet의 풀페이지 확장 API와 관련 카드 UI도 변경했습니다.

Changes

곡 등록 흐름

Layer / File(s) Summary
곡 프리뷰 데이터 계약
src/features/pin/types.ts, src/features/pin/data/songPreview.ts
Song에 아티스트 이미지를 추가하고, 곡 목록·웨이브폼·트림·태그용 데이터와 변환 함수를 정의했습니다.
곡 목록 및 라우팅
src/pages/SongListPage.tsx, src/features/pin/components/SongCard.tsx, src/routes/index.tsx
검색 가능한 곡 목록을 렌더링하고 카드 선택 시 곡 상세 경로로 이동하도록 구성했습니다.
곡 선택 BottomSheet
src/components/ui/BottomSheet.tsx, src/features/pin/components/SongSelectSheet.tsx
BottomSheet에 expand 컨텍스트 API를 추가하고, 곡 선택 시트의 기본 데이터와 레이아웃을 변경했습니다.
곡 상세 편집 화면
src/pages/SongDetailPage.tsx
곡 정보, 트림 프리뷰, 소개, 태그, 피드 공개 상태를 관리하는 상세 페이지를 추가했습니다.
PinCard 및 공통 UI 렌더링
src/features/pin/components/PinCard.tsx, src/features/pin/components/SongCard.tsx, src/components/ui/tag.tsx
카드 내부 버튼과 좋아요·등록 인원 영역을 수정하고, 곡 아티스트 이미지와 태그 기본 여백을 조정했습니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SongListPage
  participant SongDetailPage
  participant SongSelectSheet
  participant BottomSheet
  User->>SongListPage: 곡 카드 선택
  SongListPage->>SongDetailPage: 상세 경로로 이동
  User->>SongDetailPage: 곡 선택 시트 열기
  SongDetailPage->>SongSelectSheet: 시트 렌더링
  SongSelectSheet->>BottomSheet: 선택 시트 표시
  User->>SongSelectSheet: 곡 선택
  SongSelectSheet->>SongDetailPage: 선택 곡 상세 경로로 이동
Loading

Possibly related PRs

Suggested reviewers: jeonggyul, l0521

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning [#29] 검색 목록과 선택 후 이동은 보이지만, 선택 곡 정보를 상위 등록 상태에 반영하는 구현은 확인되지 않습니다. 선택 시 상위 등록 상태에 곡 정보를 저장하거나 전달하는 로직을 추가해 요구사항을 충족하세요.
Out of Scope Changes check ⚠️ Warning 상세 소개, 태그 입력, 등록 완료 처리 등 이슈에서 제외한 영역의 UI와 동작이 포함되어 있습니다. 이슈 범위 밖의 상세 입력 및 완료 처리 코드는 제거하거나 별도 PR로 분리하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 주요 변경인 노래 검색 및 곡 선택 플로우를 간결하고 명확하게 요약합니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/29-song-search-flow

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.

@kim3360
kim3360 marked this pull request as ready for review July 14, 2026 15:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/features/pin/components/SongDetailContent.tsx (2)

197-210: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

song.albumImageUrl이 앨범 이미지 렌더링에 사용되지 않음

앨범 아트가 항상 rectangleBg로 고정되어 있어, 이번 PR에서 Song 타입에 추가된 albumImageUrl 필드가 실제로 소비되지 않습니다. waveformPeaks처럼 폴백 패턴을 적용하는 것이 일관성 있습니다.

-<img src={rectangleBg} alt="" className="size-16 rounded-md object-cover" />
+<img src={song.albumImageUrl ?? rectangleBg} alt="" className="size-16 rounded-md object-cover" />
🤖 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/features/pin/components/SongDetailContent.tsx` around lines 197 - 210,
Update the album image in the SongDetailContent album art block to use
song.albumImageUrl, falling back to rectangleBg when the URL is unavailable,
consistent with the existing waveformPeaks fallback pattern. Keep the current
image styling and edit-button structure unchanged.

88-120: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

미리듣기 계산이 실제 song.duration을 반영하지 않고, 재생 버튼도 동작하지 않음

SongPreviewSectionsong.duration 대신 하드코딩된 MOCK_PREVIEW_DURATION으로 트림 구간을 계산합니다. 지금은 목데이터가 통일되어 문제가 드러나지 않지만, 실제 곡마다 길이가 다를 경우 트림 시작/끝 시간(초 단위)이 실제 재생 시간과 어긋나게 됩니다. waveformPeaks에 적용된 song.waveformPeaks ?? MOCK_WAVEFORM_PEAKS 폴백 패턴과 동일하게 song.duration ?? MOCK_PREVIEW_DURATION을 사용하는 것이 좋습니다.

또한 재생 버튼(Line 104-110)에 onClick이 없어 song.previewUrl이 전혀 사용되지 않는데, 오디오 재생 기능이 이후 작업으로 예정되어 있는지 확인이 필요합니다.

♻️ duration 폴백 적용 예시
 function SongPreviewSection({ waveformPeaks }: SongPreviewSectionProps) {
+  const duration = song.duration ?? MOCK_PREVIEW_DURATION;
   const trim = peaksToTrimRange(
     DEFAULT_TRIM_START_INDEX,
     DEFAULT_TRIM_END_INDEX,
     waveformPeaks,
-    MOCK_PREVIEW_DURATION,
+    duration,
   );

-  const trimStartPercent = timeToPercent(trim.start, MOCK_PREVIEW_DURATION);
-  const trimEndPercent = timeToPercent(trim.end, MOCK_PREVIEW_DURATION);
+  const trimStartPercent = timeToPercent(trim.start, duration);
+  const trimEndPercent = timeToPercent(trim.end, duration);

(SongPreviewSectionsong을 props로 받도록 시그니처 조정 필요)

🤖 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/features/pin/components/SongDetailContent.tsx` around lines 88 - 120,
Update SongPreviewSection to receive the song data and calculate trim
percentages using song.duration with MOCK_PREVIEW_DURATION as the fallback,
matching the existing waveformPeaks fallback pattern. Also wire the preview
button to song.previewUrl only if the current preview playback behavior is
supported; otherwise leave playback for the planned follow-up rather than adding
unrelated functionality.
🤖 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/features/pin/components/SongDetailContent.tsx`:
- Around line 21-25: Update SongDetailContentProps and the registration flow so
onRegister accepts a SongRegistration containing song, introduction, tags, and
isFeedPublic. In SongDetailContent, pass the locally edited introduction,
selectedTags, and feed visibility state when registering; update SongBottom’s
handleRegister and onSelect forwarding to propagate the complete registration
payload instead of only the original Song.

In `@src/features/pin/constants/songPreview.ts`:
- Around line 33-44: Remove the placeholder value '태그' from the TAG_OPTIONS
constant, leaving only the actual mood-tag options as selectable choices.

---

Nitpick comments:
In `@src/features/pin/components/SongDetailContent.tsx`:
- Around line 197-210: Update the album image in the SongDetailContent album art
block to use song.albumImageUrl, falling back to rectangleBg when the URL is
unavailable, consistent with the existing waveformPeaks fallback pattern. Keep
the current image styling and edit-button structure unchanged.
- Around line 88-120: Update SongPreviewSection to receive the song data and
calculate trim percentages using song.duration with MOCK_PREVIEW_DURATION as the
fallback, matching the existing waveformPeaks fallback pattern. Also wire the
preview button to song.previewUrl only if the current preview playback behavior
is supported; otherwise leave playback for the planned follow-up rather than
adding unrelated functionality.
🪄 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 Plus

Run ID: 6d446bb8-ff0d-4982-a76b-c1844d51c261

📥 Commits

Reviewing files that changed from the base of the PR and between 2c06d12 and 50b2d33.

⛔ Files ignored due to path filters (3)
  • src/assets/Rectangle.png is excluded by !**/*.png
  • src/assets/icons/pencil.svg is excluded by !**/*.svg
  • src/assets/icons/play.svg is excluded by !**/*.svg
📒 Files selected for processing (6)
  • src/components/ui/BottomSheet.tsx
  • src/features/pin/components/PinCard.tsx
  • src/features/pin/components/SongBottom.tsx
  • src/features/pin/components/SongDetailContent.tsx
  • src/features/pin/constants/songPreview.ts
  • src/types/pin.ts

Comment on lines +21 to +25
type SongDetailContentProps = {
song: Song;
onCancel: () => void;
onRegister: () => void;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

등록 시 소개/태그/피드공개 데이터가 소실됩니다

onRegister: () => void는 인자를 받지 않아, 이 컴포넌트 내부에서 관리하는 introduction, selectedTags, isFeedPublic 상태가 등록 시 상위로 전달될 방법이 없습니다. 실제로 SongBottom.tsxhandleRegisteronSelect?.(selectedSong)처럼 원본 Song 객체만 전달하며, 사용자가 입력한 소개 문구/태그/피드 공개 여부는 그대로 사라집니다. Song 타입에도 이 필드들을 담을 자리가 없습니다.

onRegister가 편집된 데이터를 인자로 전달하도록 시그니처를 변경하고, 상위(SongBottom.tsx)에서 이를 onSelect 콜백에 실어 넘기는 구조로 수정이 필요합니다.

type SongRegistration = {
  song: Song;
  introduction: string;
  tags: string[];
  isFeedPublic: boolean;
};

type SongDetailContentProps = {
  song: Song;
  onCancel: () => void;
  onRegister: (registration: SongRegistration) => void;
};

Also applies to: 151-170

🤖 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/features/pin/components/SongDetailContent.tsx` around lines 21 - 25,
Update SongDetailContentProps and the registration flow so onRegister accepts a
SongRegistration containing song, introduction, tags, and isFeedPublic. In
SongDetailContent, pass the locally edited introduction, selectedTags, and feed
visibility state when registering; update SongBottom’s handleRegister and
onSelect forwarding to propagate the complete registration payload instead of
only the original Song.

Comment thread src/features/pin/data/songPreview.ts
@kim3360
kim3360 marked this pull request as draft July 19, 2026 19:35
@onebone
onebone self-requested a review July 22, 2026 13:09
@github-actions

Copy link
Copy Markdown

https://pr-58.plimap.kr

@kim3360
kim3360 marked this pull request as ready for review July 23, 2026 18:35

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/features/pin/data/songPreview.ts (1)

41-55: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

빈 파형과 잘못된 인덱스를 정규화하세요.

peaks가 비어 있으면 0으로 나누어 CSS에 NaN%가 전달됩니다. 인덱스도 배열 범위로 제한해 트림 구간이 duration을 벗어나지 않게 하세요.

수정 예시
 export function peaksToTrimRange(
   startIndex: number,
   endIndex: number,
   peaks: readonly number[],
   duration: number,
 ) {
+  if (peaks.length === 0 || duration <= 0) {
+    return { start: 0, end: 0 };
+  }
+
+  const lastIndex = peaks.length - 1;
+  const start = Math.min(Math.max(startIndex, 0), lastIndex);
+  const end = Math.min(Math.max(endIndex, start), lastIndex);
+
   return {
-    start: (startIndex / peaks.length) * duration,
-    end: ((endIndex + 1) / peaks.length) * duration,
+    start: (start / peaks.length) * duration,
+    end: ((end + 1) / peaks.length) * duration,
   };
 }
🤖 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/features/pin/data/songPreview.ts` around lines 41 - 55, Update
peaksToTrimRange to handle an empty peaks array without division by zero,
returning a zero-length range. Clamp startIndex and endIndex to valid peak
indices, and ensure the calculated trim range remains within 0 and duration;
leave timeToPercent unchanged.
src/pages/SongDetailPage.tsx (1)

127-145: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

스위치에 접근 가능한 이름을 추가하세요.

인접 텍스트는 스위치와 연결되지 않아 스크린 리더에서 이름 없는 스위치로 읽힙니다.

     <button
       type="button"
       role="switch"
+      aria-label="피드 공개"
       aria-checked={checked}
🤖 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/pages/SongDetailPage.tsx` around lines 127 - 145, Update the switch
button’s accessible naming in the JSX by adding an accessible name that
identifies the setting controlled by this toggle. Keep the existing role,
aria-checked state, click behavior, and visual styling 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/pages/SongListPage.tsx`:
- Around line 14-29: Connect SearchInput to local search state by supplying its
value and onChange handler, then derive the rendered song list from
MOCK_SONG_CARD_LIST filtered by matching title or artist text. Update the map in
SongListPage to render the filtered results while preserving existing navigation
behavior.

In `@src/routes/index.tsx`:
- Around line 52-55: Remove the standalone `pin/search` route from the route
configuration near `PinPlaceSearchPage`, leaving only the `MapLayout` route
hierarchy with the `mapOverlay` handle for this path. Preserve the overlay
route’s existing behavior and avoid defining `/app/pin/search` in a second
route.

---

Outside diff comments:
In `@src/features/pin/data/songPreview.ts`:
- Around line 41-55: Update peaksToTrimRange to handle an empty peaks array
without division by zero, returning a zero-length range. Clamp startIndex and
endIndex to valid peak indices, and ensure the calculated trim range remains
within 0 and duration; leave timeToPercent unchanged.

In `@src/pages/SongDetailPage.tsx`:
- Around line 127-145: Update the switch button’s accessible naming in the JSX
by adding an accessible name that identifies the setting controlled by this
toggle. Keep the existing role, aria-checked state, click behavior, and visual
styling 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 Plus

Run ID: dfcdce59-54df-4d3d-8425-afa345021631

📥 Commits

Reviewing files that changed from the base of the PR and between 50b2d33 and 12e1561.

📒 Files selected for processing (8)
  • src/components/ui/BottomSheet.tsx
  • src/features/pin/components/SongCard.tsx
  • src/features/pin/components/SongSelectSheet.tsx
  • src/features/pin/data/songPreview.ts
  • src/features/pin/types.ts
  • src/pages/SongDetailPage.tsx
  • src/pages/SongListPage.tsx
  • src/routes/index.tsx

Comment thread src/pages/SongListPage.tsx Outdated
Comment thread src/routes/index.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/pages/SongDetailPage.tsx (3)

127-131: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

switch에 접근 가능한 이름을 연결하세요.

role="switch"aria-checked는 있지만 aria-label 또는 aria-labelledby가 없어 스크린 리더가 이 컨트롤의 의미를 알 수 없습니다. aria-label="피드 공개"를 추가하거나 Line 276의 텍스트를 aria-labelledby로 연결하세요.

🤖 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/pages/SongDetailPage.tsx` around lines 127 - 131, SongDetailPage의 switch
버튼에 접근 가능한 이름이 없습니다. 해당 button에 aria-label="피드 공개"를 추가하거나, Line 276의 관련 텍스트를
가리키는 aria-labelledby를 연결하여 스크린 리더가 컨트롤의 의미를 인식하도록 수정하세요.

85-94: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

선택된 곡의 프리뷰 데이터를 사용해야 합니다.

현재 SongDetailPage는 항상 MOCK_WAVEFORM_PEAKSMOCK_PREVIEW_DURATION을 사용합니다. 따라서 곡을 변경해도 제목·커버만 바뀌고 waveform 및 trim 시간은 이전 mock 계약과 무관하게 고정됩니다. song.waveformPeakssong.durationSongPreviewSection에 전달하세요.

Also applies to: 159-160

🤖 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/pages/SongDetailPage.tsx` around lines 85 - 94, Update SongDetailPage and
SongPreviewSection to use the selected song’s preview data instead of mock
constants: pass song.waveformPeaks and song.duration into SongPreviewSection,
then use those props for peaksToTrimRange and timeToPercent. Remove the preview
calculations’ dependency on MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION while
preserving the existing trim indices.

154-157: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

곡 변경 시 이전 곡의 편집 상태를 초기화해야 합니다.

SongDetailPageuseParamssongId를 받지만 useEffectkey로 곡 ID 변경을 감지하지 않아, 곡 선택으로 이동해도 introduction, selectedTags, isFeedPublic이 이전 곡의 값으로 유지됩니다. 새로운 곡의 저장 폼 상태는 초기화하고, 저장 데이터는 songId를 저장할 때만 적용하세요.

🤖 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/pages/SongDetailPage.tsx` around lines 154 - 157, Update SongDetailPage
to detect songId changes from useParams and reset introduction, selectedTags,
and isFeedPublic to the new song’s defaults when the selected song changes.
Apply persisted saved data only for the current songId, and ensure the form
state cannot carry over from the previously selected song.
🤖 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/features/pin/components/SongCard.tsx`:
- Around line 15-17: Update the thumbnail wrapper in SongCard to include
overflow-hidden alongside rounded-[4px], ensuring the img respects the wrapper’s
rounded corners while preserving the existing sizing and styling.

---

Outside diff comments:
In `@src/pages/SongDetailPage.tsx`:
- Around line 127-131: SongDetailPage의 switch 버튼에 접근 가능한 이름이 없습니다. 해당 button에
aria-label="피드 공개"를 추가하거나, Line 276의 관련 텍스트를 가리키는 aria-labelledby를 연결하여 스크린 리더가
컨트롤의 의미를 인식하도록 수정하세요.
- Around line 85-94: Update SongDetailPage and SongPreviewSection to use the
selected song’s preview data instead of mock constants: pass song.waveformPeaks
and song.duration into SongPreviewSection, then use those props for
peaksToTrimRange and timeToPercent. Remove the preview calculations’ dependency
on MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION while preserving the existing
trim indices.
- Around line 154-157: Update SongDetailPage to detect songId changes from
useParams and reset introduction, selectedTags, and isFeedPublic to the new
song’s defaults when the selected song changes. Apply persisted saved data only
for the current songId, and ensure the form state cannot carry over from the
previously selected song.
🪄 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 Plus

Run ID: 44d3a911-af83-48c5-8b39-ab72003989a8

📥 Commits

Reviewing files that changed from the base of the PR and between 12e1561 and 70f6671.

📒 Files selected for processing (3)
  • src/features/pin/components/SongCard.tsx
  • src/features/pin/components/SongSelectSheet.tsx
  • src/pages/SongDetailPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/features/pin/components/SongSelectSheet.tsx

Comment thread src/features/pin/components/SongCard.tsx Outdated
Comment thread src/pages/SongDetailPage.tsx Outdated

function SongWaveform({ peaks, trimStartIndex, trimEndIndex }: SongWaveformProps) {
return (
<div className="flex h-[72px] items-center gap-[2px]" aria-hidden>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

gap 6px인 것 같아요!

Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

수정 완료

Comment thread src/pages/SongDetailPage.tsx Outdated
Comment on lines +229 to +246

<SongPreviewSection waveformPeaks={waveformPeaks} />
</div>
</div>
</section>

<section className="flex flex-col gap-3 px-[15px]">
<h3 className="body-15-r text-grayscale-300">소개</h3>
<div className="relative rounded-xl bg-pli-black-85 p-5">
<label htmlFor="song-intro" className="sr-only">
소개
</label>
<textarea
id="song-intro"
value={introduction}
onChange={(event) => setIntroduction(event.target.value.slice(0, INTRO_MAX_LENGTH))}
placeholder="이 음악을 들었을 때 나의 기분은?"
className="body-17-r min-h-[120px] w-full resize-none text-grayscale-300 outline-none placeholder:text-grayscale-1100"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

디테일이기는 한데요, 뒤에 보이는 노래 커버가 소개까지 안 가고 중간에 끊기는 것 같아요! 그리고 블러도 의도보다 강하게 먹여진 것 같습니당

피그마:
Image

구현:

Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

수정 완료하였습니다.

Comment thread src/pages/SongDetailPage.tsx Outdated
Comment on lines +241 to +246
<textarea
id="song-intro"
value={introduction}
onChange={(event) => setIntroduction(event.target.value.slice(0, INTRO_MAX_LENGTH))}
placeholder="이 음악을 들었을 때 나의 기분은?"
className="body-17-r min-h-[120px] w-full resize-none text-grayscale-300 outline-none placeholder:text-grayscale-1100"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이거 textarea의 min-height가 120px로 설정되어 있는데 피그마에서는 88px부터 시작인 것 같아요!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

피그마에 textarea 높이가 156px이라 맞게 수정 하였습니다.

Comment thread src/pages/SongDetailPage.tsx Outdated
Comment on lines +258 to +272
<div className="flex flex-wrap justify-between gap-y-3 pt-3">
{TAG_OPTIONS.map((tag) => {
const isSelected = selectedTags.includes(tag);

return (
<Tag
key={tag}
variant={isSelected ? 'selected' : 'default'}
onClick={() => toggleTag(tag)}
>
#{tag}
</Tag>
);
})}
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

루트 레이아웃 크기를 320px로 줄이면 이렇게 떠요! justify-between 때문에 그런 것 같아서 justify-start가 나을지 좀 고민되네용

이거 개수가 안 맞을 때는 항상 이렇게 뜰 것 같아서 고민해봐야 할 것 같습니다!

Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

justify-start로 주면 gap도 추가 필요한데 전에 gap 넣으면 디자인 패딩과 맞지가 않아서 다른 문제가 발생합니다. 전에 fs데이에서 태그는 8개로만 고정이라고 들은거 같은데 기획자랑 디자이너 얘기 한 번 다시 해보겠습니다.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

아 지금 보니까 화면 줄이고 나서군요 수정 해보겠습니다.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

수정 하였습니다.

@onebone
onebone force-pushed the feat/29-song-search-flow branch from 33fab6c to 47ee46e Compare July 24, 2026 15:52
@onebone onebone added the feature Feature implementation label Jul 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/features/pin/components/PinCard.tsx`:
- Around line 38-45: PinCard의 버튼 표시에서 정의되지 않은 pinCount 참조를 제거하고, 주변 데이터 구조에 맞춰
pin.pinCount를 사용하도록 수정하세요.
🪄 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 Plus

Run ID: 95edad43-35c7-4cef-bad0-25bb915aab02

📥 Commits

Reviewing files that changed from the base of the PR and between 70f6671 and 74f199c.

📒 Files selected for processing (6)
  • src/features/pin/components/PinCard.tsx
  • src/features/pin/components/SongCard.tsx
  • src/features/pin/data/songPreview.ts
  • src/pages/SongDetailPage.tsx
  • src/pages/SongListPage.tsx
  • src/routes/index.tsx
💤 Files with no reviewable changes (1)
  • src/routes/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/features/pin/data/songPreview.ts
  • src/features/pin/components/SongCard.tsx
  • src/pages/SongListPage.tsx
  • src/pages/SongDetailPage.tsx

Comment thread src/features/pin/components/PinCard.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/pages/SongDetailPage.tsx (4)

127-131: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

스위치에 접근 가능한 이름을 부여하세요.

현재 role="switch" 버튼에는 aria-label이나 aria-labelledby가 없어 스크린 리더에서 이름 없는 스위치로 인식됩니다. aria-label="피드 공개" 등을 추가해 주세요.

수정 예시
     <button
       type="button"
       role="switch"
+      aria-label="피드 공개"
       aria-checked={checked}
🤖 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/pages/SongDetailPage.tsx` around lines 127 - 131, Update the switch
button in SongDetailPage around the checked/onChange handlers to provide an
accessible name, using an appropriate aria-label such as “피드 공개” or an existing
associated label via aria-labelledby. Preserve the current switch role, checked
state, and toggle behavior.

150-152: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

잘못된 songId를 첫 번째 곡으로 대체하지 마세요.

존재하지 않는 ID로 접근하면 사용자가 요청한 곡 대신 첫 번째 곡이 표시됩니다. 잘못된 ID는 Not Found 화면을 보여주거나 곡 목록으로 리다이렉트해야 합니다.

🤖 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/pages/SongDetailPage.tsx` around lines 150 - 152, Update the song lookup
in SongDetailPage so an invalid songId does not fall back to
MOCK_SONG_CARD_LIST[0]. Preserve the found song behavior, and render the
existing Not Found state or redirect to the song list when no matching item
exists.

85-94: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

선택된 곡의 프리뷰 데이터를 사용해야 합니다.

현재 다른 곡을 선택해도 MOCK_WAVEFORM_PEAKSMOCK_PREVIEW_DURATION으로 웨이브폼과 트림 위치를 계산합니다. 제목과 커버만 바뀌고 프리뷰는 고정된 곡의 데이터로 표시됩니다. 선택된 songwaveformPeaksdurationSongPreviewSection에 전달하세요.

Also applies to: 110-113, 159-160

🤖 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/pages/SongDetailPage.tsx` around lines 85 - 94, SongPreviewSection
currently calculates the preview with fixed MOCK_WAVEFORM_PEAKS and
MOCK_PREVIEW_DURATION instead of the selected song’s data. Update SongDetailPage
and SongPreviewSection to pass and use the selected song’s waveformPeaks and
duration, including trim and waveform rendering paths, while preserving the
existing preview behavior for the provided song data.

154-156: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

곡 변경 시 상세 상태를 초기화하거나 곡별로 분리해야 합니다.

같은 라우트에서 songId만 변경되므로 useState 값은 유지됩니다. 따라서 곡 A의 소개·태그·공개 설정이 곡 B에 그대로 남을 수 있습니다. songId 변경 시 상태를 초기화하거나 곡별 상태로 관리하세요.

Also applies to: 283-285

🤖 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/pages/SongDetailPage.tsx` around lines 154 - 156, SongDetailPage의
introduction, selectedTags, isFeedPublic 상태가 songId 변경 시 유지되지 않도록 songId를 의존성으로
하는 초기화 처리를 추가하세요. 곡이 바뀌면 세 상태를 각 상태의 기본값으로 재설정하거나 새 곡의 상세 데이터로 갱신하고, 기존 곡 내 편집
흐름은 유지하세요.
🤖 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.

Outside diff comments:
In `@src/pages/SongDetailPage.tsx`:
- Around line 127-131: Update the switch button in SongDetailPage around the
checked/onChange handlers to provide an accessible name, using an appropriate
aria-label such as “피드 공개” or an existing associated label via aria-labelledby.
Preserve the current switch role, checked state, and toggle behavior.
- Around line 150-152: Update the song lookup in SongDetailPage so an invalid
songId does not fall back to MOCK_SONG_CARD_LIST[0]. Preserve the found song
behavior, and render the existing Not Found state or redirect to the song list
when no matching item exists.
- Around line 85-94: SongPreviewSection currently calculates the preview with
fixed MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION instead of the selected
song’s data. Update SongDetailPage and SongPreviewSection to pass and use the
selected song’s waveformPeaks and duration, including trim and waveform
rendering paths, while preserving the existing preview behavior for the provided
song data.
- Around line 154-156: SongDetailPage의 introduction, selectedTags, isFeedPublic
상태가 songId 변경 시 유지되지 않도록 songId를 의존성으로 하는 초기화 처리를 추가하세요. 곡이 바뀌면 세 상태를 각 상태의
기본값으로 재설정하거나 새 곡의 상세 데이터로 갱신하고, 기존 곡 내 편집 흐름은 유지하세요.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: be8f1f83-6757-4299-86b6-6a09ccb12968

📥 Commits

Reviewing files that changed from the base of the PR and between 74f199c and 2d89592.

📒 Files selected for processing (3)
  • src/components/ui/tag.tsx
  • src/features/pin/components/PinCard.tsx
  • src/pages/SongDetailPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/features/pin/components/PinCard.tsx

This branch was successfully deployed

1 active and 1 inactive deployments
preview-maintenance c653baa7 Deployed Jul 25, 2026 by kim3360 via cleanup #94
preview c653baa7 Deployed Jul 25, 2026 by kim3360 via deploy #93
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Feature implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

노래 검색 및 곡 선택 플로우 구현

3 participants