Skip to content

Feat/scroll text#150

Merged
GulSam00 merged 11 commits intodevelopfrom
feat/scrollText
Mar 2, 2026
Merged

Feat/scroll text#150
GulSam00 merged 11 commits intodevelopfrom
feat/scrollText

Conversation

@GulSam00
Copy link
Owner

@GulSam00 GulSam00 commented Mar 2, 2026

📌 PR 제목

Feat/scroll text

📌 변경 사항

  • 스크롤 텍스트 기능 추가
  • 곡 추천 페이지 UI 개선
  • 검색 페이지 toggle해서 펼치기 UI 개선

💬 추가 참고 사항

@vercel
Copy link
Contributor

vercel bot commented Mar 2, 2026

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

Project Deployment Actions Updated (UTC)
singcode Ready Ready Preview, Comment Mar 2, 2026 8:12am

@qodo-code-review
Copy link

Review Summary by Qodo

Add auto-scrolling text, collapsible search UI, and ranking page recommendations

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Add MarqueeText component for auto-scrolling text display
• Implement collapsible UI for search results with smooth animations
• Add song recommendation feature to ranking page with thumb count display
• Improve recent songs page with dropdown selectors for year/month
• Update check-in reward points from 10 to 30
• Fix database queries to use release date instead of created_at
• Integrate thumb count into search results and song cards
Diagram
flowchart LR
  A["MarqueeText Component"] --> B["Auto-scroll Long Text"]
  C["Search Results"] --> D["Collapsible Button UI"]
  D --> E["Animated Expand/Collapse"]
  F["Ranking Page"] --> G["Thumb Count Display"]
  G --> H["Recommendation Modal"]
  I["Recent Songs Page"] --> J["Year/Month Dropdowns"]
  K["Database"] --> L["Use Release Date"]
  M["Check-in Reward"] --> N["30 Points"]
Loading

Grey Divider

File Changes

1. apps/web/src/components/MarqueeText.tsx ✨ Enhancement +53/-0

New MarqueeText component for auto-scrolling

apps/web/src/components/MarqueeText.tsx


2. apps/web/src/app/api/search/route.ts ✨ Enhancement +17/-6

Add total_stats to search query and response

apps/web/src/app/api/search/route.ts


3. apps/web/src/app/api/songs/recent-add/route.ts 🐞 Bug fix +3/-3

Fix query to use release date field

apps/web/src/app/api/songs/recent-add/route.ts


View more (20)
4. apps/web/src/app/api/user/check-in/route.ts ✨ Enhancement +1/-1

Increase check-in reward points to 30

apps/web/src/app/api/user/check-in/route.ts


5. apps/web/src/types/song.ts ✨ Enhancement +1/-0

Add thumb field to Song interface

apps/web/src/types/song.ts


6. apps/web/src/globals.css ✨ Enhancement +16/-0

Add marquee animation keyframes

apps/web/src/globals.css


7. apps/web/src/queries/songThumbQuery.ts 🐞 Bug fix +1/-0

Invalidate search query on thumb mutation

apps/web/src/queries/songThumbQuery.ts


8. apps/web/src/app/search/SearchResultCard.tsx ✨ Enhancement +104/-57

Add collapsible buttons with animations

apps/web/src/app/search/SearchResultCard.tsx


9. apps/web/src/app/search/HomePage.tsx Miscellaneous +0/-2

Remove debug console log

apps/web/src/app/search/HomePage.tsx


10. apps/web/src/app/search/MusicCard.tsx ✨ Enhancement +6/-4

Apply MarqueeText to music card titles

apps/web/src/app/search/MusicCard.tsx


11. apps/web/src/app/search/AddFolderModal.tsx ✨ Enhancement +3/-2

Apply MarqueeText to modal song info

apps/web/src/app/search/AddFolderModal.tsx


12. apps/web/src/app/recent/page.tsx ✨ Enhancement +46/-20

Replace buttons with dropdown selectors

apps/web/src/app/recent/page.tsx


13. apps/web/src/app/recent/RecentSongCard.tsx ✨ Enhancement +4/-3

Apply MarqueeText to song titles

apps/web/src/app/recent/RecentSongCard.tsx


14. apps/web/src/app/popular/PopularRankingList.tsx ✨ Enhancement +23/-18

Move ScrollArea into component and adjust layout

apps/web/src/app/popular/PopularRankingList.tsx


15. apps/web/src/app/popular/page.tsx ✨ Enhancement +2/-5

Remove ScrollArea wrapper from page

apps/web/src/app/popular/page.tsx


16. apps/web/src/components/RankingItem.tsx ✨ Enhancement +77/-8

Add recommendation button and song details

apps/web/src/components/RankingItem.tsx


17. apps/web/src/components/ThumbUpModal.tsx ✨ Enhancement +37/-4

Display thumb count and song info in modal

apps/web/src/components/ThumbUpModal.tsx


18. apps/web/src/app/tosing/SongCard.tsx ✨ Enhancement +5/-4

Apply MarqueeText to song card text

apps/web/src/app/tosing/SongCard.tsx


19. apps/web/src/app/tosing/ModalSongItem.tsx ✨ Enhancement +3/-2

Apply MarqueeText to modal song items

apps/web/src/app/tosing/ModalSongItem.tsx


20. apps/web/package.json ⚙️ Configuration changes +1/-1

Bump version to 2.3.0

apps/web/package.json


21. apps/web/public/changelog.json 📝 Documentation +7/-0

Add version 2.3.0 changelog entry

apps/web/public/changelog.json


22. README.md 📝 Documentation +1/-0

Add version 2.3.0 release notes

README.md


23. apps/web/src/app/info/like/SongItem.tsx Additional files +3/-2

...

apps/web/src/app/info/like/SongItem.tsx


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 2, 2026

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Song.thumb contract mismatch🐞 Bug ✓ Correctness
Description
Song.thumb was made required, but multiple API routes still return song objects without any
thumb value (thumbs live in total_stats.total_thumb). This creates inconsistent runtime shapes
(likely undefined) and can cause incorrect UI/logic when any downstream code relies on thumb.
Code

apps/web/src/types/song.ts[R4-7]

artist: string;
num_tj: string;
num_ky: string;
+  thumb: number;
Evidence
The PR makes thumb mandatory on the base Song type, but the codebase stores thumbs in
total_stats.total_thumb (not in songs). Only the search API explicitly joins total_stats to
synthesize thumb, while other endpoints (tosing/like/save/recent-add and guest tosing) fetch from
songs (or build objects) without joining total_stats, so they cannot reliably populate the
required thumb field.

apps/web/src/types/song.ts[1-11]
apps/web/src/app/api/songs/thumb-up/route.ts[55-73]
apps/web/src/app/api/search/route.ts[49-57]
apps/web/src/app/api/search/route.ts[77-87]
apps/web/src/app/api/songs/tosing/route.ts[13-25]
apps/web/src/app/api/songs/tosing/guest/route.ts[18-36]
apps/web/src/app/api/songs/like/route.ts[32-41]
apps/web/src/app/api/songs/save/route.ts[31-43]
apps/web/src/app/api/songs/recent-add/route.ts[24-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Song.thumb` is now required, but most endpoints return songs without joining `total_stats`, so they cannot populate `thumb`. This produces inconsistent runtime data (likely `undefined`) while TypeScript assumes a `number`.
### Issue Context
- Thumbs are stored/updated in `total_stats.total_thumb`.
- Only `/api/search` joins `total_stats` to provide `thumb`.
- Other routes return song objects without `thumb`.
### Fix Focus Areas
- apps/web/src/types/song.ts[1-11]
- apps/web/src/app/api/search/route.ts[49-57]
- apps/web/src/app/api/songs/tosing/route.ts[13-25]
- apps/web/src/app/api/songs/tosing/guest/route.ts[18-36]
- apps/web/src/app/api/songs/like/route.ts[32-41]
- apps/web/src/app/api/songs/save/route.ts[31-43]
- apps/web/src/app/api/songs/recent-add/route.ts[24-35]
- apps/web/src/app/api/songs/thumb-up/route.ts[55-73]
### Suggested approach
1. Change the base `Song` type to not require `thumb` (either remove it or make it optional).
2. Introduce a separate type for UI models that include thumb (e.g., `SongWithThumb` / keep `SearchSong` requiring `thumb`).
3. Where thumb is needed outside search/ranking, update those APIs to join `total_stats` and map `thumb` explicitly (defaulting to 0).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Song.thumb contract mismatch🐞 Bug ✓ Correctness
Description
Song.thumb was made required, but multiple API routes still return song objects without any
thumb value (thumbs live in total_stats.total_thumb). This creates inconsistent runtime shapes
(likely undefined) and can cause incorrect UI/logic when any downstream code relies on thumb.
Code

apps/web/src/types/song.ts[R4-7]

 artist: string;
 num_tj: string;
 num_ky: string;
+  thumb: number;
Evidence
The PR makes thumb mandatory on the base Song type, but the codebase stores thumbs in
total_stats.total_thumb (not in songs). Only the search API explicitly joins total_stats to
synthesize thumb, while other endpoints (tosing/like/save/recent-add and guest tosing) fetch from
songs (or build objects) without joining total_stats, so they cannot reliably populate the
required thumb field.

apps/web/src/types/song.ts[1-11]
apps/web/src/app/api/songs/thumb-up/route.ts[55-73]
apps/web/src/app/api/search/route.ts[49-57]
apps/web/src/app/api/search/route.ts[77-87]
apps/web/src/app/api/songs/tosing/route.ts[13-25]
apps/web/src/app/api/songs/tosing/guest/route.ts[18-36]
apps/web/src/app/api/songs/like/route.ts[32-41]
apps/web/src/app/api/songs/save/route.ts[31-43]
apps/web/src/app/api/songs/recent-add/route.ts[24-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Song.thumb` is now required, but most endpoints return songs without joining `total_stats`, so they cannot populate `thumb`. This produces inconsistent runtime data (likely `undefined`) while TypeScript assumes a `number`.
### Issue Context
- Thumbs are stored/updated in `total_stats.total_thumb`.
- Only `/api/search` joins `total_stats` to provide `thumb`.
- Other routes return song objects without `thumb`.
### Fix Focus Areas
- apps/web/src/types/song.ts[1-11]
- apps/web/src/app/api/search/route.ts[49-57]
- apps/web/src/app/api/songs/tosing/route.ts[13-25]
- apps/web/src/app/api/songs/tosing/guest/route.ts[18-36]
- apps/web/src/app/api/songs/like/route.ts[32-41]
- apps/web/src/app/api/songs/save/route.ts[31-43]
- apps/web/src/app/api/songs/recent-add/route.ts[24-35]
- apps/web/src/app/api/songs/thumb-up/route.ts[55-73]
### Suggested approach
1. Change the base `Song` type to not require `thumb` (either remove it or make it optional).
2. Introduce a separate type for UI models that include thumb (e.g., `SongWithThumb` / keep `SearchSong` requiring `thumb`).
3. Where thumb is needed outside search/ranking, update those APIs to join `total_stats` and map `thumb` explicitly (defaulting to 0).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Recent-add range includes next🐞 Bug ✓ Correctness
Description
The recent-add API uses lte(endDate) where endDate is the first day of the next month, so
boundary timestamps can be included in the wrong month. It also compares release using ISO
timestamps even though release is typed as an optional string, risking mismatched comparisons.
Code

apps/web/src/app/api/songs/recent-add/route.ts[R28-30]

+      .gte('release', startDate.toISOString())
+      .lte('release', endDate.toISOString())
+      .order('release', { ascending: false })
Evidence
endDate is computed as new Date(year, month + 1, 1) (the start of the next month) and is used
with an inclusive .lte() filter, which can include records exactly at the boundary. Additionally,
release is modeled as a string in the app types, but the query compares it to toISOString()
timestamps, which may not match the stored format depending on how release is stored.

apps/web/src/app/api/songs/recent-add/route.ts[19-31]
apps/web/src/types/song.ts[7-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The month filter for recent songs uses an inclusive upper bound at the next-month boundary (`lte(endDate)` where `endDate` is the first day of the next month). This can include next-month records at the boundary and is prone to format/timezone issues.
### Issue Context
- `endDate = new Date(year, month + 1, 1)`.
- Query uses `.lte('release', endDate.toISOString())`.
- `Song.release` is typed as `string | undefined`, so the DB may not store it as an ISO timestamp.
### Fix Focus Areas
- apps/web/src/app/api/songs/recent-add/route.ts[19-31]
- apps/web/src/types/song.ts[7-10]
### Suggested approach
1. Change `.lte('release', endDate.toISOString())` to `.lt('release', endDate.toISOString())`.
2. If `release` is a DATE (no time), compare using date strings (e.g., `YYYY-MM-DD`) or use appropriate DB casting.
3. Consider filtering out null releases if needed (e.g., `.not('release', 'is', null)`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Recent-add range includes next🐞 Bug ✓ Correctness
Description
The recent-add API uses lte(endDate) where endDate is the first day of the next month, so
boundary timestamps can be included in the wrong month. It also compares release using ISO
timestamps even though release is typed as an optional string, risking mismatched comparisons.
Code

apps/web/src/app/api/songs/recent-add/route.ts[R28-30]

+      .gte('release', startDate.toISOString())
+      .lte('release', endDate.toISOString())
+      .order('release', { ascending: false })
Evidence
endDate is computed as new Date(year, month + 1, 1) (the start of the next month) and is used
with an inclusive .lte() filter, which can include records exactly at the boundary. Additionally,
release is modeled as a string in the app types, but the query compares it to toISOString()
timestamps, which may not match the stored format depending on how release is stored.

apps/web/src/app/api/songs/recent-add/route.ts[19-31]
apps/web/src/types/song.ts[7-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The month filter for recent songs uses an inclusive upper bound at the next-month boundary (`lte(endDate)` where `endDate` is the first day of the next month). This can include next-month records at the boundary and is prone to format/timezone issues.
### Issue Context
- `endDate = new Date(year, month + 1, 1)`.
- Query uses `.lte('release', endDate.toISOString())`.
- `Song.release` is typed as `string | undefined`, so the DB may not store it as an ISO timestamp.
### Fix Focus Areas
- apps/web/src/app/api/songs/recent-add/route.ts[19-31]
- apps/web/src/types/song.ts[7-10]
### Suggested approach
1. Change `.lte('release', endDate.toISOString())` to `.lt('release', endDate.toISOString())`.
2. If `release` is a DATE (no time), compare using date strings (e.g., `YYYY-MM-DD`) or use appropriate DB casting.
3. Consider filtering out null releases if needed (e.g., `.not('release', 'is', null)`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Search overfetches total_stats 🐞 Bug ➹ Performance
Description
The search API selects total_stats (*) but only uses total_thumb; fetching all total_stats
columns for every row increases payload size and DB work on every search request.
Code

apps/web/src/app/api/search/route.ts[R50-57]

+      const baseQuery = supabase.from('songs').select(
+        `*, 
+        total_stats (
+          *
+        )
+        `,
+        { count: 'exact' },
+      );
Evidence
Both authenticated and unauthenticated search queries request all columns from total_stats, while
the response mapping only reads total_thumb. This is unnecessary overfetch.

apps/web/src/app/api/search/route.ts[50-57]
apps/web/src/app/api/search/route.ts[77-87]
apps/web/src/app/api/search/route.ts[99-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Search endpoint overfetches `total_stats(*)` but only needs `total_thumb`, increasing response size and query cost.
### Issue Context
This endpoint is called frequently (search UI) and returns paginated lists.
### Fix Focus Areas
- apps/web/src/app/api/search/route.ts[50-57]
- apps/web/src/app/api/search/route.ts[99-116]
- apps/web/src/app/api/search/route.ts[77-87]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. MarqueeText observer per item 🐞 Bug ➹ Performance
Description
MarqueeText creates a new ResizeObserver per instance; the PR replaces many list item
titles/artists with this component, which can become expensive if many items are rendered
simultaneously (many observers + state updates on resizes/layout changes).
Code

apps/web/src/components/MarqueeText.tsx[R24-29]

+  useEffect(() => {
+    checkOverflow();
+    const resizeObserver = new ResizeObserver(() => checkOverflow());
+    if (containerRef.current) resizeObserver.observe(containerRef.current);
+    return () => resizeObserver.disconnect();
+  }, [children]);
Evidence
The component instantiates and attaches a ResizeObserver in an effect. The PR adds MarqueeText into
list-like UI components (e.g., search results and ranking items), increasing the number of observers
created at once.

apps/web/src/components/MarqueeText.tsx[24-29]
apps/web/src/app/search/SearchResultCard.tsx[68-76]
apps/web/src/components/RankingItem.tsx[70-73]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`MarqueeText` allocates a `ResizeObserver` per rendered instance. With many items on screen, this can add overhead.
### Issue Context
PR introduces `MarqueeText` usage across multiple list UIs (search results, ranking list, recent cards, modals).
### Fix Focus Areas
- apps/web/src/components/MarqueeText.tsx[24-29]
- apps/web/src/app/search/SearchResultCard.tsx[68-76]
- apps/web/src/components/RankingItem.tsx[70-73]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@GulSam00
Copy link
Owner Author

GulSam00 commented Mar 2, 2026

/describe: Describe this PR (이 PR을 설명해 주세요.)
/review: Review this PR (이 PR을 리뷰해 주세요.)
/improve: Improve this PR (이 PR을 개선해 주세요.)

@GulSam00
Copy link
Owner Author

GulSam00 commented Mar 2, 2026

/review

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 2, 2026

Persistent review updated to latest commit 0f8f405

@GulSam00
Copy link
Owner Author

GulSam00 commented Mar 2, 2026

/improve

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 2, 2026

Persistent review updated to latest commit 0f8f405

@GulSam00 GulSam00 merged commit f062777 into develop Mar 2, 2026
2 checks passed
@GulSam00 GulSam00 deleted the feat/scrollText branch March 2, 2026 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 인기곡 페이지 UI 개선 [FEAT] 스크롤 텍스트 기능

1 participant