Skip to content

Conversation

@hongik-luke
Copy link

@hongik-luke hongik-luke commented Jan 1, 2026

๐Ÿ’ก To Reviewers

โš ๏ธํ˜„์žฌ PR์˜ base๊ฐ€ feat-8๋กœ ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค ๋ฐ˜๋“œ์‹œ feat-8์„ ๋จผ์ € mergeํ•˜๊ณ  mergeํ•ด ์ฃผ์‹œ๊ณ  feat-8๊ณผ ๊ด€๋ จ๋œ commit์€ ์ œ ์ž‘์—…๋ฌผ์ด ์•„๋‹™๋‹ˆ๋‹ค ์ด๋ฅผ ์ฐธ๊ณ  ๋ฐ”๋ž๋‹ˆ๋‹ค.โš ๏ธ
์ด PR์€ feat-10 ์ž‘์—…์ž…๋‹ˆ๋‹ค.
์›๋ณธ ๋ ˆํฌ์— push ๊ถŒํ•œ์ด ์—†์–ด์„œ fork์—์„œ PR ์˜ฌ๋ ธ์Šต๋‹ˆ๋‹ค
โš ๏ธFigma์— component ๋ชจ์•„์ ธ์žˆ๋Š” ๊ณณ์— ์ด๋ฆ„์„ ํŒŒ์ผ์ด๋ฆ„๊ณผ ๋™์ผํ•˜๊ฒŒ ์ˆ˜์ •ํ•ด๋‘์—ˆ์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ฐพ์œผ์‹œ๊ธฐ ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.โš ๏ธ

๐Ÿ”ฅ ์ž‘์—… ๋‚ด์šฉ (๊ฐ€๋Šฅํ•œ ๊ตฌ์ฒด์ ์œผ๋กœ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”)

  1. ํŒŒ์ผ๊ตฌ์กฐ

  2. [global css] ๊ธ€์”จ์ฒด, ์ƒ‰ ํ˜ธ์ถœ๋ฐฉ๋ฒ•

  3. button_without_img

  4. ๊ฐ ํŽ˜์ด์ง€ ๋ณ„ ์ƒ์„ฑํ•œ ui

  5. ํŒŒ์ผ๊ตฌ์กฐ
    src/components/base_ui
    -> ํ•˜์œ„
    /home
    /Auth
    /Group-search
    /Group-create
    /BookStory
    /News
    /Search
    /Profile
    /Settings
    /button_without_img.tsx

  6. [global css] ๊ธ€์”จ์ฒด, ์ƒ‰ ํ˜ธ์ถœ๋ฐฉ๋ฒ•

ex)


Subhead_4_1 ->

/* Subhead_4.1 /
font-family: "Pretendard Variable";
font-size: 18px;
font-style: normal;
font-weight: 500;
line-height: 135%; /
24.3px /
letter-spacing: -0.018px;
๊ฐ€ ํ˜ธ์ถœ๋จ
๊ธ€์”จ์ฒด ์ƒ์œ„์— /
Subhead_4.1 */ ์ด๋ ‡๊ฒŒ ํ‘œ๊ธฐ๋˜์–ด ์žˆ์œผ๋‹ˆ ํ˜ธ์ถœํ•˜์‹œ๊ณ  ์ƒ‰๋งŒ ์‹ ๊ฒฝ์จ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
ํ˜ธ์ถœ ๊ทœ์น™

  1. ์ด๋ฆ„: ๋Œ€์†Œ๋ฌธ์ž ํฌํ•จ ๊ทธ๋Œ€๋กœ

  2. [.] ์€ _๋กœ ๋Œ€์ฒด

  3. ์ƒ‰ ํ† ํฐ์€ Gray_7 ๊ฐ™์€ ํ˜•์‹ ( ex text-[color:var(--Gray_7)]

  4. button_without_img

์ด๋ฏธ์ง€๊ฐ€ ์—†์„ ์‹œ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ ํผ
์‚ฌ์šฉ ์˜ˆ์‹œ (๋น„์–ด์žˆ์„ ์‹œ ๊ธฐ๋ณธ๊ฐ’์ด ๋“ค์–ด๊ฐ)

  1. ์ƒ‰ : ๋ฐฐ๊ฒฝ ํ…Œ๋‘๋ฆฌ ํ…์ŠคํŠธ ์„ค์ •๊ฐ€๋Šฅ
  2. ํ˜ธ๋ฒ„ ์‹œ ์ƒ‰๋„ ์„ค์ •๊ฐ€๋Šฅ
  3. ํฌ๊ธฐ ์„ค์ • ๊ฐ€๋Šฅ
    ์•„๋ฌด ๋‚ด์šฉ ์—†์„ ์‹œ์— ๊ธฐ๋ณธ๊ฐ’์ด ๋“ค์–ด๊ฐ

// ์•„๋ž˜ ๊ธฐ๋ณธ๊ฐ’ ๊ฒธ ์‚ฌ์šฉ๋ฐฉ๋ฒ•
<ButtonWithoutImg
text="๋“ฑ๋ก"
onClick={() => {} }

bgColorVar="--premary_2"
borderColorVar="--premary_2"
textColorVar="--White"

hoverBgColorVar="--premary_2"
hoverBorderColorVar="--premary_2"
hoverTextColorVar="--White"

width={132}
height={44}
/>

  1. ๊ฐ ํŽ˜์ด์ง€ ๋ณ„ ์ƒ์„ฑํ•œ ui

์ฑ…๋ชจ_ํ™ˆํ™”๋ฉด

  1. home_bookclub -> ๋ชจ์ž„๊ฐฏ์ˆ˜์— ๋”ฐ๋ฅธ ๊ฒฝ์šฐ๋ฅผ ๋ชจ๋‘ ํ•˜๋‚˜์— ๋‹ด์•˜์Šต๋‹ˆ๋‹ค.
  2. list_subscribe_element
  3. notification_element
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 061131 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 063708

๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž…
๊ฐœ๋ณ„๋กœ ๋งŒ๋“œ๋Š”๊ฒŒ ๋‚˜์•„๋ณด์—ฌ ์ƒ๋žตํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋ชจ์ž„ ๊ฒ€์ƒ‰ / ๋ชจ์ž„ ์ƒ์„ฑ
-> ์ œ ์ชฝ์ด๋ผ์„œ ์ผ๋‹จ ๋ณด๋ฅ˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฑ…์ด์•ผ๊ธฐ

  1. bookstory_choosebook
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 074003 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 074038
  1. bookstory_detail
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 084650
  1. bookstory_text
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 080234 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 0802457

์†Œ์‹

  1. news_list
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 090134 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 090201
  1. recommendbook_element
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 094101 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 094114

๊ฒ€์ƒ‰

  1. recommendbook_element
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 100923
  1. search_bookresult
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 100708

๋งˆ์ดํŽ˜์ด์ง€&๋‹ค๋ฅธ์‚ฌ๋žŒ ํ”„๋กœํ•„

  1. mypage_profile
  2. others_profile
ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 104835 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 105907
  1. notification_element
    ํ™ˆํ™”๋ฉด์— ์žˆ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค ๊ณ ๋กœ ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค notification_element

  2. subscribe

ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 111532 ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 111544

์„ค์ •

  1. setting_news_list
    ์†Œ์‹์˜ news_list์™€ maxํฌ๊ธฐ ๋นผ๊ณค ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค ๊ณ ๋กœ ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค.

  2. setting_report_list

ํ™”๋ฉด ์บก์ฒ˜ 2026-01-01 112710

๐Ÿค” ์ถ”ํ›„ ์ž‘์—… ์˜ˆ์ •

๋ชจ์ž„ ๊ฒ€์ƒ‰ / ๋ชจ์ž„ ์ƒ์„ฑ

๐Ÿ“ธ ์ž‘์—… ๊ฒฐ๊ณผ (์Šคํฌ๋ฆฐ์ƒท)

๐Ÿ”— ๊ด€๋ จ ์ด์Šˆ

Feat-10

Summary by CodeRabbit

Release Notes

  • New Features

    • Added main navigation header with menu links and action icons
    • Introduced book story feature with book selection and detail displays
    • Added profile management pages (personal and others' profiles)
    • Implemented news feed and search functionality
    • Added notification system for user interactions
    • Introduced book club/group sidebar widget
    • New settings pages for news and report management
  • Style

    • Implemented comprehensive design system with color tokens and typography utilities
    • Updated default font to Pretendard for improved typography

โœ๏ธ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 1, 2026

๐Ÿ“ Walkthrough

Walkthrough

This PR establishes a foundational design system with CSS tokens and typography utilities, introduces a main app layout structure with supporting pages, and adds an extensive library of reusable UI components across feature areas including book stories, profiles, news, search, settings, and home features.

Changes

Cohort / File(s) Summary
Configuration & Styling
src/app/globals.css, tsconfig.json, src/app/layout.tsx
Added comprehensive CSS design tokens (color palette, grayscale, secondary, subbrown, primary) and typography utility classes (Headlines, Subheads, Body, Caption variants); updated font-family to Pretendard; reformatted tsconfig.json to multi-line config and added .next type paths.
Layout & Pages
src/app/(main)/layout.tsx, src/app/(main)/page.tsx, src/app/(main)/ui-test/page.tsx
Introduced new main layout component wrapping a Header, created HomePage as empty container, and added UiTestClient page for component testing with a Setting_ReportList instance.
Layout Components
src/components/layout/Header.tsx, src/components/layout/NavItem.tsx
Implemented Header component with navigation menu, search/notification/profile icons, and active state tracking via usePathname; added NavItem for styled navigation links.
BookStory Components
src/components/base-ui/BookStory/bookstory_choosebook.tsx, src/components/base-ui/BookStory/bookstory_detail.tsx, src/components/base-ui/BookStory/bookstory_text.tsx
Added BookstoryChoosebook for book selection card, BookstoryDetail for two-column layout (image + author/book info), and BookstoryText for title/detail input with auto-resizing textarea and Tab indentation handling.
Profile Components
src/components/base-ui/Profile/mypage_profile.tsx, src/components/base-ui/Profile/others_profile.tsx, src/components/base-ui/Profile/subscribe_element.tsx, src/components/base-ui/Profile/notification_element.tsx
Created MypageProfile for user header with stats and actions, OthersProfile with subscribe/report buttons, Subscribe element for horizontal subscription card, and NotificationElement for notification items with type-based messaging.
News & Recommendation Components
src/components/base-ui/News/news_list.tsx, src/components/base-ui/News/recommendbook_element.tsx, src/components/base-ui/Settings/setting_news_list.tsx
Introduced NewsList for news items with image/title/content/date layout, BookCoverCard for book cover with like toggle, and Setting_NewsList variant for settings context.
Search Components
src/components/base-ui/Search/search_bookresult.tsx, src/components/base-ui/Search/search_recommendbook.tsx
Added SearchBookResult for book search results with like and pencil actions, and Search_BookCoverCard for recommendation display with like and click handlers.
Settings Components
src/components/base-ui/Settings/setting_report_list.tsx
Implemented Setting_ReportList rendering report items with badge, reporter name, date, and content in horizontal layout.
Home Components
src/components/base-ui/home/home_bookclub.tsx, src/components/base-ui/home/list_subscribe_element.tsx, src/components/base-ui/home/notification_element.tsx
Created HomeBookclub collapsible widget for group listings, ListSubscribeElement for user subscription tiles, and NotificationElement for notification display with type-based messaging.
Base UI Utility
src/components/base-ui/button_without_img.tsx
Added ButtonWithoutImg component with configurable colors via CSS variables, hover states, and disabled styling.
Issue Template
.github/ISSUE_TEMPLATE/custom.md
Updated template with double-quoted strings for metadata fields and added "๊ธฐํƒ€ (์„ค๋ช… ์ถ”๊ฐ€)" option to issue type list; added guidance notes for feature and reference sections.

Estimated code review effort

๐ŸŽฏ 3 (Moderate) | โฑ๏ธ ~25 minutes

Poem

๐Ÿฐ A warren of components now hop into place,
With tokens and layouts that structure the space,
ProfilePage, Header, and BookStory too,
Design system tokens make everything new!
From search to settings, each piece fits just right,
The foundation is built, shining clear and bright! โœจ

Pre-merge checks and finishing touches

โŒ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage โš ๏ธ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check โ“ Inconclusive The pull request title 'Feat 10' is vague and generic, using a non-descriptive term that does not convey meaningful information about the changeset. Use a more descriptive title that summarizes the main changes, such as 'Add base UI components and global design system' or similar.
โœ… Passed checks (1 passed)
Check name Status Explanation
Description Check โœ… Passed Check skipped - CodeRabbitโ€™s high-level summary is enabled.
โœจ Finishing touches
  • ๐Ÿ“ Generate docstrings

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.

@gemini-code-assist
Copy link

Summary of Changes

Hello @hongik-luke, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

์ด PR์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ•ต์‹ฌ UI ์ปดํฌ๋„ŒํŠธ์™€ ๊ธฐ๋ณธ ๋ ˆ์ด์•„์›ƒ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ํŽ˜์ด์ง€์— ํ•„์š”ํ•œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ UI ์š”์†Œ๋“ค์„ ์ •์˜ํ•˜๊ณ , ์ผ๊ด€๋œ ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ์œ„ํ•œ ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ๋ฐ ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ๋ฅผ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ–ฅํ›„ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์˜ ๊ธฐ๋ฐ˜์„ ๋งˆ๋ จํ•˜๊ณ  ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์˜ ์ผ๊ด€์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

Highlights

  • ์ƒˆ๋กœ์šด UI ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐํ™”: src/components/base_ui ์•„๋ž˜์— ํŽ˜์ด์ง€๋ณ„(Home, Auth, Group-search, Group-create, BookStory, News, Search, Profile, Settings) ๋ฐ ๊ณตํ†ต(button_without_img) ์ปดํฌ๋„ŒํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ์ •์˜: globals.css์— ์ƒˆ๋กœ์šด ์ƒ‰์ƒ ํ† ํฐ ๋ฐ Pretendard Variable ํฐํŠธ๋ฅผ ์ ์šฉํ•˜๊ณ , ๋‹ค์–‘ํ•œ ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค(Headline, Subhead, Body, Caption)๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ: ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ๋ฒ”์šฉ ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ(button_without_img.tsx)๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋ฐฐ๊ฒฝ์ƒ‰, ํ…Œ๋‘๋ฆฌ์ƒ‰, ํ…์ŠคํŠธ์ƒ‰, ํ˜ธ๋ฒ„ ์ƒํƒœ ์ƒ‰์ƒ, ํฌ๊ธฐ ๋“ฑ์„ ์œ ์—ฐํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํŽ˜์ด์ง€๋ณ„ UI ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ: ํ™ˆ ํ™”๋ฉด, ์ฑ… ์ด์•ผ๊ธฐ, ์†Œ์‹, ๊ฒ€์ƒ‰, ๋งˆ์ดํŽ˜์ด์ง€/ํ”„๋กœํ•„, ์„ค์ • ๋“ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ฃผ์š” ํŽ˜์ด์ง€์— ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ UI ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๊ฐœ๋ฐœํ•˜์—ฌ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ ๋ฐ ํ—ค๋”: src/app/(main)/layout.tsx์— ๋ฉ”์ธ ๋ ˆ์ด์•„์›ƒ์„ ์ถ”๊ฐ€ํ•˜๊ณ , Header.tsx ๋ฐ NavItem.tsx ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ๋‚ด๋น„๊ฒŒ์ด์…˜ ํ—ค๋”๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด SVG ์•„์ด์ฝ˜ ์ถ”๊ฐ€: public ๋””๋ ‰ํ† ๋ฆฌ์— ArrowDown, ArrowTop, Edit_icon, Setting_icon, gray_heart, icon_plus, logo, logo2, notification, pencil_icon, plus, profile, red_heart, search ๋“ฑ ๋‹ค์–‘ํ•œ SVG ์•„์ด์ฝ˜์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿง  New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with ๐Ÿ‘ and ๐Ÿ‘Ž on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. โ†ฉ

@github-actions
Copy link

github-actions bot commented Jan 1, 2026

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

์ด PR์€ ์ƒˆ๋กœ์šด UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋Œ€๊ฑฐ ์ถ”๊ฐ€ํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ์™€ ์ „์—ญ ์Šคํƒ€์ผ์„ ์„ค์ •ํ•˜๋Š” ์ค‘์š”ํ•œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์ธ ๊ตฌ์กฐ๋Š” ์ข‹์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ ๊ฐœ์„ ์ ์ด ํ•„์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. home_bookclub.tsx์—์„œ ๋กœ์ง ๋ฐ ์Šคํƒ€์ผ๋ง๊ณผ ๊ด€๋ จ๋œ ๋ช‡ ๊ฐ€์ง€ ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์œผ๋ฉฐ, button_without_img.tsx์—์„œ๋Š” hover ํšจ๊ณผ ๊ตฌํ˜„ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๊ฐœ์„ ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ(news_list, notification_element)์— ๊ฑธ์ณ ์ฝ”๋“œ ์ค‘๋ณต์ด ์ƒ๋‹นํ•˜์—ฌ ๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์™ธ์—๋„ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ƒ‰์ƒ, ์ผ๊ด€์„ฑ ์—†๋Š” ์ด๋ฆ„ ์ง€์ •, ์ ‘๊ทผ์„ฑ ๋ฌธ์ œ(๋Œ€์ฒด ํ…์ŠคํŠธ/๋ ˆ์ด๋ธ” ๋ˆ„๋ฝ) ๋“ฑ์ด ๋‹ค์ˆ˜ ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ฐœ๋ณ„ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

text-[13px] flex items-center justify-center gap-2"
>
<Image src="/icon_plus.svg" alt="icon_plus" width={24} height={24} />
<span className="text-color-white Subhead_4_1">๋ชจ์ž„ ์ƒ์„ฑํ•˜๊ธฐ</span>

Choose a reason for hiding this comment

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

critical

text-color-white๋Š” ์œ ํšจํ•œ Tailwind ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. text-white๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Suggested change
<span className="text-color-white Subhead_4_1">๋ชจ์ž„ ์ƒ์„ฑํ•˜๊ธฐ</span>
<span className="text-white Subhead_4_1">๋ชจ์ž„ ์ƒ์„ฑํ•˜๊ธฐ</span>

>
{open ? (
<div className="flex items-center justify-center gap-1">
<span className="text-[color:var(--Gray_7)] Body_1_2 font-weight: 500">์ ‘๊ธฐ</span>

Choose a reason for hiding this comment

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

critical

className ๋ฌธ์ž์—ด ์•ˆ์— font-weight: 500๊ณผ ๊ฐ™์€ ์ผ๋ฐ˜ CSS ์†์„ฑ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. Tailwind CSS์—์„œ๋Š” font-medium๊ณผ ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Suggested change
<span className="text-[color:var(--Gray_7)] Body_1_2 font-weight: 500">์ ‘๊ธฐ</span>
<span className="text-[color:var(--Gray_7)] Body_1_2 font-medium">์ ‘๊ธฐ</span>

key={group.id}
className="flex w-[288px] h-[52px] py-3 px-4 items-center rounded-lg bg-white"
>
<span className="text-[color:var(--Gray--7)] h-6 Subhead_4_1 ">

Choose a reason for hiding this comment

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

critical

CSS ๋ณ€์ˆ˜ ์ด๋ฆ„์— ์˜คํƒ€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. --Gray--7์ด ์•„๋‹ˆ๋ผ --Gray_7์ด ์˜ฌ๋ฐ”๋ฅธ ๋ณ€์ˆ˜๋ช…์ž…๋‹ˆ๋‹ค. ์ด ์˜คํƒ€๋กœ ์ธํ•ด ์Šคํƒ€์ผ์ด ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Suggested change
<span className="text-[color:var(--Gray--7)] h-6 Subhead_4_1 ">
<span className="text-[color:var(--Gray_7)] h-6 Subhead_4_1 ">


export default function HomeBookclub({ groups }: Props) {
const count = groups.length;
const isMany = count >= 5;

Choose a reason for hiding this comment

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

critical

๋ชจ์ž„ ๋ชฉ๋ก์„ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ์ง์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. isMany์˜ ์กฐ๊ฑด์ด count >= 5์ธ๋ฐ, 5๊ฐœ ๋˜๋Š” 6๊ฐœ์˜ ๊ทธ๋ฃน์ด ์žˆ์„ ๋•Œ "์ „์ฒด๋ณด๊ธฐ" ๋ฒ„ํŠผ์ด ํ‘œ์‹œ๋˜์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์ด ์ด๋ฏธ ํ™”๋ฉด์— ๋ณด์ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํ˜ผ๋™ํ•˜์ง€ ์•Š๋„๋ก, "์ „์ฒด๋ณด๊ธฐ" ๋ฒ„ํŠผ์€ ์‹ค์ œ๋กœ ์ˆจ๊ฒจ์ง„ ํ•ญ๋ชฉ์ด ์žˆ์„ ๋•Œ๋งŒ (์˜ˆ: count > 6) ๋‚˜ํƒ€๋‚˜๋„๋ก ์กฐ๊ฑด์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Suggested change
const isMany = count >= 5;
const isMany = count > 6;

Comment on lines +1 to +55
"use client";
import Image from "next/image";

type NewsListProps = {
imageUrl: string;
title: string;
content: string;
date: string; // "2025-10-09" ๊ฐ™์€ ๋ฌธ์ž์—ด
className?: string;
};

export default function Setting_NewsList({
imageUrl,
title,
content,
date,
className = "",
}: NewsListProps) {
return (
<div
className={[
"inline-flex w-full max-w-[1000px] p-[20px] items-start",
"rounded-[8px] border border-[color:var(--Subbrown_4,#EAE5E2)] bg-white gap-6",
className,
].join(" ")}
>
{/* left image */}
<div className="relative w-[100px] h-[145px] shrink-0 ">
<Image
src={imageUrl}
alt={title}
fill
sizes="100px"
className="object-cover"
/>
</div>

{/* middle + right */}
<div className="flex flex-1 min-w-0 items-start">
{/* middle text */}
<div className="flex flex-col gap-[8px] min-w-0 flex-1">
<p className="text-[#000] Subhead_3 truncate">{title}</p>
<p className="text-[color:var(--Gray_4,#8D8D8D)] Body_1_2 line-clamp-6">
{content}
</p>
</div>

{/* ์ตœ์†Œ 120px ํ™•๋ณด + ๋‚ ์งœ ์˜ค๋ฅธ์ชฝ ๊ณ ์ • */}
<div className="shrink-0 min-w-[180px] text-right">
<p className="text-[color:var(--Gray_3,#BBB)] Body_1_2">{date}</p>
</div>
</div>
</div>
);
}

Choose a reason for hiding this comment

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

high

์ด ์ปดํฌ๋„ŒํŠธ๋Š” src/components/base-ui/News/news_list.tsx์™€ max-w ํด๋ž˜์Šค๋ฅผ ์ œ์™ธํ•˜๊ณ  ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ ์ค‘๋ณต์€ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ NewsList ์ปดํฌ๋„ŒํŠธ๋กœ ํ†ตํ•ฉํ•˜๊ณ , className์ด๋‚˜ maxWidth ๊ฐ™์€ prop์„ ํ†ตํ•ด ์Šคํƒ€์ผ์„ ๋™์ ์œผ๋กœ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

<div className="flex flex-1 min-w-0 items-start">
{/* middle text */}
<div className="flex flex-col gap-[8px] min-w-0 flex-1">
<p className="text-[#000] Subhead_3 truncate">{title}</p>

Choose a reason for hiding this comment

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

medium

์ƒ‰์ƒ ๊ฐ’ #000์ด ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. globals.css์— ์ •์˜๋œ --Black CSS ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ด์ฃผ์„ธ์š”.

Suggested change
<p className="text-[#000] Subhead_3 truncate">{title}</p>
<p className="text-[color:var(--Black)] Subhead_3 truncate">{title}</p>

authorNickname: string;
authorId: string | number;

profileImgSrc?: string; // ๊ธฐ๋ณธ: "/profile.svg"

Choose a reason for hiding this comment

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

medium

profileImgSrc prop์˜ ๊ธฐ๋ณธ๊ฐ’์— ๋Œ€ํ•œ ์ฃผ์„์ด ์‹ค์ œ ์ฝ”๋“œ์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฃผ์„์—๋Š” "/profile.svg"๋กœ ๋˜์–ด์žˆ์ง€๋งŒ, ์ฝ”๋“œ์—์„œ๋Š” "/profile2.svg"๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์„์„ ์‹ค์ œ ์ฝ”๋“œ์™€ ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜์—ฌ ํ˜ผ๋™์„ ๋ฐฉ์ง€ํ•ด์ฃผ์„ธ์š”.

Suggested change
profileImgSrc?: string; // ๊ธฐ๋ณธ: "/profile.svg"
profileImgSrc?: string; // ๊ธฐ๋ณธ: "/profile2.svg"

</div>
) : (
<div className="flex items-center justify-center gap-1">
<span className="text-[color:var(--Gray_7)] Body_1_2 Body_1_2">์ „์ฒด๋ณด๊ธฐ</span>

Choose a reason for hiding this comment

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

medium

Body_1_2 ํด๋ž˜์Šค๊ฐ€ ์ค‘๋ณต์œผ๋กœ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”.

Suggested change
<span className="text-[color:var(--Gray_7)] Body_1_2 Body_1_2">์ „์ฒด๋ณด๊ธฐ</span>
<span className="text-[color:var(--Gray_7)] Body_1_2">์ „์ฒด๋ณด๊ธฐ</span>

Comment on lines +61 to +63
border border-[color:var(--premary_2,#9A7A6B)]
bg-[color:var(--background,#F9F7F6)]
text-[color:var(--premary_2,#9A7A6B)]

Choose a reason for hiding this comment

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

medium

CSS ๋ณ€์ˆ˜ ์ด๋ฆ„์— ์˜คํƒ€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. premary_2๊ฐ€ ์•„๋‹ˆ๋ผ primary_2๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ๋ณ€์ˆ˜๋ช…์ž…๋‹ˆ๋‹ค. ์ด ์˜คํƒ€๋กœ ์ธํ•ด ์Šคํƒ€์ผ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ ์šฉ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Suggested change
border border-[color:var(--premary_2,#9A7A6B)]
bg-[color:var(--background,#F9F7F6)]
text-[color:var(--premary_2,#9A7A6B)]
border border-[color:var(--primary_2,#9A7A6B)]
bg-[color:var(--background,#F9F7F6)]
text-[color:var(--primary_2,#9A7A6B)]

Comment on lines +40 to +41
<p className="text-[#000] Subhead_3 truncate">{bookName}</p>
<p className="text-[#757575] Subhead_4_1 truncate">{author}</p>

Choose a reason for hiding this comment

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

medium

์ƒ‰์ƒ ๊ฐ’์ด ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด globals.css์— ์ •์˜๋œ CSS ๋ณ€์ˆ˜(์˜ˆ: var(--Black), var(--Gray_5))๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”.

Suggested change
<p className="text-[#000] Subhead_3 truncate">{bookName}</p>
<p className="text-[#757575] Subhead_4_1 truncate">{author}</p>
<p className="text-[color:var(--Black)] Subhead_3 truncate">{bookName}</p>
<p className="text-[color:var(--Gray_5)] Subhead_4_1 truncate">{author}</p>

Copy link

@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: 11

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

โ™ป๏ธ Duplicate comments (2)
src/components/base-ui/home/notification_element.tsx (1)

1-47: LGTM!

The component logic is correct. The conditional rendering for the latest notification indicator and the message construction based on type are well-implemented. Note: duplication with Profile/notification_element.tsx was flagged in the other file's review.

src/components/base-ui/News/news_list.tsx (1)

1-55: Code duplication with Setting_NewsList component.

This component is nearly identical to src/components/base-ui/Settings/setting_news_list.tsx. The duplication concern and refactoring recommendation have been documented in the review of that file.

๐ŸŸก Minor comments (10)
src/components/base-ui/home/home_bookclub.tsx-72-72 (1)

72-72: Remove duplicate class.

Body_1_2 is specified twice.

๐Ÿ”Ž Proposed fix
-                <span className="text-[color:var(--Gray_7)] Body_1_2 Body_1_2">์ „์ฒด๋ณด๊ธฐ</span>
+                <span className="text-[color:var(--Gray_7)] Body_1_2">์ „์ฒด๋ณด๊ธฐ</span>
src/components/base-ui/home/home_bookclub.tsx-49-51 (1)

49-51: Fix CSS variable name typo.

--Gray--7 (double dash) should be --Gray_7 (underscore) to match the design system convention used elsewhere.

๐Ÿ”Ž Proposed fix
-              <span className="text-[color:var(--Gray--7)] h-6 Subhead_4_1 ">
+              <span className="text-[color:var(--Gray_7)] h-6 Subhead_4_1">
src/components/base-ui/home/home_bookclub.tsx-67-68 (1)

67-68: Invalid CSS syntax in className.

font-weight: 500 is CSS syntax, not a valid Tailwind class. Use font-medium instead.

๐Ÿ”Ž Proposed fix
-                <span className="text-[color:var(--Gray_7)] Body_1_2 font-weight: 500">์ ‘๊ธฐ</span>
+                <span className="text-[color:var(--Gray_7)] Body_1_2 font-medium">์ ‘๊ธฐ</span>
src/components/base-ui/home/home_bookclub.tsx-63-63 (1)

63-63: Fix CSS variable name typo.

--Gray--3 should be --Gray_3 to match the design system convention.

๐Ÿ”Ž Proposed fix
-            className="w-full h-[38px] rounded-[6px] bg-transparent text-[13px] flex items-center justify-center gap-[6px] text-[color:var(--Gray--3)]"
+            className="w-full h-[38px] rounded-[6px] bg-transparent text-[13px] flex items-center justify-center gap-[6px] text-[color:var(--Gray_3)]"
src/components/base-ui/home/list_subscribe_element.tsx-24-32 (1)

24-32: Fix sizes prop mismatch.

The container is 32x32 but sizes="42px". These should match for optimal image loading.

๐Ÿ”Ž Proposed fix
-          sizes="42px"
+          sizes="32px"
src/components/base-ui/home/home_bookclub.tsx-32-33 (1)

32-33: Fix image path and use Next.js Image component.

The src is missing a leading / and uses a native <img> instead of Next.js Image, which is inconsistent with the rest of the component.

๐Ÿ”Ž Proposed fix
-          <img src="logo2.svg" alt= "๋กœ๊ณ " className="mx-auto mb-4 mt-[118px]" />
+          <Image src="/logo2.svg" alt="๋กœ๊ณ " width={100} height={100} className="mx-auto mb-4 mt-[118px]" />

Committable suggestion skipped: line range outside the PR's diff.

src/components/base-ui/Profile/mypage_profile.tsx-7-7 (1)

7-7: Update comment to match implementation.

The comment states the default is /profile.svg, but line 25 uses /profile3.svg as the default value.

๐Ÿ”Ž Fix comment
-  profileImgSrc?: string; // default: /profile.svg
+  profileImgSrc?: string; // default: /profile3.svg
src/components/base-ui/Profile/mypage_profile.tsx-6-22 (1)

6-22: Export the MypageProfileProps type.

The type is not exported, making it unavailable to consumers who might need it for type-safe prop passing or composition. This is inconsistent with the PR summary, which indicates the type should be part of the public API surface.

๐Ÿ”Ž Add export keyword
-type MypageProfileProps = {
+export type MypageProfileProps = {
   profileImgSrc?: string; // default: /profile.svg
   name: string;
src/components/base-ui/Search/search_bookresult.tsx-55-55 (1)

55-55: Fix typo: flex1 should be flex-1.

The className flex1 is not a valid Tailwind utility. This should be flex-1 to apply the flexbox grow property.

๐Ÿ”Ž Proposed fix
-          <p className="flex1 h-full text-[color:var(--Gray_4,#8D8D8D)] Body_1_2 line-clamp-6">
+          <p className="flex-1 h-full text-[color:var(--Gray_4,#8D8D8D)] Body_1_2 line-clamp-6">
             {clippedDetail}
           </p>
src/components/base-ui/Search/search_recommendbook.tsx-35-35 (1)

35-35: Image sizes attribute doesn't match container dimensions.

The container width is 332px, but the sizes attribute is set to "244px". This mismatch may cause Next.js to fetch a suboptimally-sized image, affecting performance and quality.

๐Ÿ”Ž Suggested fix
-      <Image src={coverSrc} alt={title} fill sizes="244px" className="object-cover" />
+      <Image src={coverSrc} alt={title} fill sizes="332px" className="object-cover" />

Alternatively, if the image area is intended to be smaller due to padding or other factors, adjust the sizes value to match the actual rendered width.

๐Ÿงน Nitpick comments (21)
src/components/base-ui/Profile/notification_element.tsx (1)

1-47: Consolidate duplicate notification components.

This component is nearly identical to src/components/base-ui/home/notification_element.tsx. Both define the same types (NotificationType, NotificationElementProps), the same logic, and the same rendering. Consider extracting a single shared NotificationElement component (e.g., in a common/ or shared/ folder) and importing it where needed, rather than maintaining two copies.

src/components/base-ui/Profile/others_profile.tsx (2)

17-17: Remove unused onSettings prop.

onSettings is declared in the type but never destructured or used in the component.

๐Ÿ”Ž Proposed fix
-  onSettings?: () => void;

100-103: Consider guarding optional callback.

onReportClick is optional, but unlike onToggleSubscribe, it's passed directly to onClick. For consistency and to prevent potential issues, consider using optional chaining.

๐Ÿ”Ž Proposed fix
-          onClick={onReportClick}
+          onClick={() => onReportClick?.()}
src/components/base-ui/home/list_subscribe_element.tsx (1)

49-49: Remove redundant color classes.

text-white and text-[color:var(--White,#FFF)] are redundant; keep one for consistency with the design system.

๐Ÿ”Ž Proposed fix
-        className="flex px-[17px] py-[8px] justify-center items-center gap-[10px] rounded-[8px] bg-[#9A7A6B] text-white text-[color:var(--White,#FFF)] text-[12px] font-semibold leading-[100%] tracking-[-0.012px] whitespace-nowrap"
+        className="flex px-[17px] py-[8px] justify-center items-center gap-[10px] rounded-[8px] bg-[color:var(--primary_2,#9A7A6B)] text-[color:var(--White,#FFF)] text-[12px] font-semibold leading-[100%] tracking-[-0.012px] whitespace-nowrap"
src/components/base-ui/BookStory/bookstory_text.tsx (3)

20-27: Consider a flicker-free approach for textarea auto-resize.

Setting height to "0px" forces a reflow and can cause a visible flash as the textarea shrinks momentarily before expanding to scrollHeight. Consider using height: "auto" instead or maintaining a minimum height to reduce this flicker.

๐Ÿ”Ž Alternative approach to reduce flicker
  useLayoutEffect(() => {
    const el = textareaRef.current;
    if (!el) return;

-   el.style.height = "0px"; // ๋จผ์ € ์ค„์—ฌ์„œ scrollHeight ์ •ํ™•ํžˆ ๊ณ„์‚ฐ
+   el.style.height = "auto"; // Avoids visible shrinking
    el.style.height = `${el.scrollHeight}px`;
  }, [detail]);

82-82: Remove redundant rows attribute.

Since the textarea height is dynamically controlled via the useLayoutEffect hook, the rows={6} attribute has no practical effect and can be removed for clarity.

๐Ÿ”Ž Suggested cleanup
        <textarea
          ref={textareaRef}
          value={detail}
          onChange={(e) => onChangeDetail(e.target.value)}
          onKeyDown={handleDetailKeyDown}
          placeholder="๋‚ด์šฉ์„ ์ž์œ ๋กญ๊ฒŒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
-         rows={6}
          className="
            w-full resize-none bg-transparent outline-none
            text-[color:var(--Gray_7,#2C2C2C)] Subhead_4_1
            placeholder:text-[color:var(--Gray_3,#BBB)]
            whitespace-pre-wrap
          "
        />

5-10: Consider using export type for type-only exports.

For better tree-shaking and explicit intent, use the export type syntax when exporting type definitions.

๐Ÿ”Ž TypeScript best practice
-type BookstoryTextProps = {
+export type BookstoryTextProps = {
  title: string;
  detail: string;
  onChangeTitle: (v: string) => void;
  onChangeDetail: (v: string) => void;
};
src/components/base-ui/BookStory/bookstory_choosebook.tsx (1)

13-49: Consider simplifying CSS variable syntax for Tailwind v4.

The component structure and Next.js Image usage are solid. However, Tailwind CSS v4 introduces a cleaner syntax for CSS variables: you can use border-(--Subbrown_4) and text-(--Gray_4) instead of border-[color:var(--Subbrown_4)] and text-[color:var(--Gray_4)]. The current syntax still works but is more verbose than necessary.

Optional: Tailwind v4 CSS variable syntax
-    <div className={`w-full max-w-[1040px] flex items-center p-[20px] ${className} bg-white border border-[color:var(--Subbrown_4)] rounded-[8px]`}>
+    <div className={`w-full max-w-[1040px] flex items-center p-[20px] ${className} bg-white border border-(--Subbrown_4) rounded-[8px]`}>
-          <p className="mt-[12px] text-[color:var(--Gray_4,#8D8D8D)] Body_1_2 line-clamp-4 overflow-hidden">
+          <p className="mt-[12px] text-(--Gray_4) Body_1_2 line-clamp-4 overflow-hidden">

Note: If you want to keep the fallback color #8D8D8D, you can define it in your @theme directive or keep the current syntax.

src/components/base-ui/Profile/mypage_profile.tsx (3)

38-42: Consider simplifying className concatenation.

The array-join pattern for className composition is verbose. Template literals or a utility like clsx/cn would be more concise and maintainable.

Alternative approaches

Using template literal:

className={`w-[734px] h-[244px] flex flex-col ${className}`}

Or with clsx (if available in the project):

className={clsx("w-[734px] h-[244px] flex flex-col", className)}

60-60: Consider extracting hard-coded strings for internationalization.

Multiple UI strings are hard-coded in Korean ("๊ตฌ๋…์ค‘", "๊ตฌ๋…์ž", "ํ”„๋กœํ•„ ํŽธ์ง‘", "์ฑ… ์ด์•ผ๊ธฐ ์“ฐ๊ธฐ", "์†Œ์‹ ๋ฌธ์˜ํ•˜๊ธฐ"). While this may be acceptable for the current scope, consider extracting these strings to support future internationalization or easier text updates.

Also applies to: 66-66, 94-94, 123-123, 138-138


111-139: Consider extracting shared button styles.

The two action buttons have identical styling with only content and click handlers differing. Consider extracting to a shared component or constant, or leveraging the ButtonWithoutImg component mentioned in the PR description.

Example refactor
const actionButtonClass = `
  flex w-[355px] h-[48px] px-[16px] py-[12px]
  justify-center items-center gap-[10px]
  rounded-[8px]
  bg-[color:var(--Primary_1,#7B6154)]
  text-[color:var(--White,#FFF)] Subhead_4_1
  whitespace-nowrap
`;

// Then use:
<button onClick={onLeftButtonClick} className={actionButtonClass}>
  ์ฑ… ์ด์•ผ๊ธฐ ์“ฐ๊ธฐ
</button>
src/components/base-ui/News/recommendbook_element.tsx (1)

5-15: Consider exporting the BookCoverCardProps type.

The BookCoverCardProps type is not currently exported. If other components or tests need to reference this type externally, consider adding export before type.

๐Ÿ”Ž Proposed fix to export the type
-type BookCoverCardProps = {
+export type BookCoverCardProps = {
src/components/base-ui/BookStory/bookstory_detail.tsx (1)

7-24: Consider exporting the BookstoryDetailProps type.

Similar to the News component, the BookstoryDetailProps type is not exported. If external components or tests need to reference this type, consider adding the export keyword.

๐Ÿ”Ž Proposed fix to export the type
-type BookstoryDetailProps = {
+export type BookstoryDetailProps = {
src/app/globals.css (1)

70-70: Consider separating truncate from Body_1.

The Body_1 utility includes truncate, which forces all text using this class to be truncated. This may not be desirable in all use cases. Consider creating a separate variant (e.g., Body_1_truncate) or removing truncate from the base utility to allow more flexible usage.

๐Ÿ”Ž Proposed refactor
  /* Body */
- .Body_1 { @apply text-[14px] font-semibold leading-[145%] tracking-[-0.014px] truncate; }
+ .Body_1 { @apply text-[14px] font-semibold leading-[145%] tracking-[-0.014px]; }
  .Body_1_1 { @apply text-[14px] font-semibold leading-[145%] tracking-[-0.014px]; }

This aligns Body_1 with the naming pattern of other variants (Body_1_1, Body_1_2, etc.) where Body_1 would be the base and you can add truncate inline where needed: Body_1 truncate.

src/app/(main)/page.tsx (1)

1-3: Placeholder implementation detected.

The home page currently renders an empty div. Based on the PR objectives mentioning home UI components (home_bookclub, list_subscribe_element, notification_element), this page should eventually integrate those components to display the actual home page content.

Would you like me to open an issue to track the integration of home UI components into this page?

src/components/layout/NavItem.tsx (1)

13-16: Consider using a className utility for cleaner conditional styling.

The array .join(" ") pattern works but is verbose. Consider using clsx or a cn utility function for more maintainable conditional className composition.

๐Ÿ”Ž Refactor using clsx utility

First, install clsx if not already present:

npm install clsx

Then refactor the component:

 import Link from "next/link";
+import clsx from "clsx";

 interface NavItemProps {
   href: string;
   label: string;
   active: boolean;
 }

 export function NavItem({ href, label, active }: NavItemProps) {
   return (
     <Link
       href={href}
-      className={[
-        "flex w-32 items-center justify-center gap-2.5 p-2.5",
-        active ? "border-b-2 border-white" : "border-b-2 border-transparent",
-      ].join(" ")}
+      className={clsx(
+        "flex w-32 items-center justify-center gap-2.5 p-2.5",
+        active ? "border-b-2 border-white" : "border-b-2 border-transparent"
+      )}
     >
       <span
-        className={[
-          "text-center text-xl font-semibold leading-7",
-          active ? "text-white" : "text-gray-200",
-        ].join(" ")}
+        className={clsx(
+          "text-center text-xl font-semibold leading-7",
+          active ? "text-white" : "text-gray-200"
+        )}
       >
         {label}
       </span>
     </Link>
   );
 }

Also applies to: 19-22

src/components/base-ui/button_without_img.tsx (1)

52-77: Consider using CSS :hover instead of manual state.

The manual hover state management with useState causes re-renders on every mouse enter/leave event. Since you're already using transition-colors, you could simplify this with pure CSS using the :hover pseudo-class and CSS variables.

๐Ÿ”Ž Alternative CSS-only hover approach
 export default function ButtonWithoutImg({
   text,
   onClick,
   bgColorVar = "--primary_2",
   borderColorVar = "--primary_2",
   textColorVar = "--White",
   hoverBgColorVar,
   hoverBorderColorVar,
   hoverTextColorVar,
   width = 132,
   height = 44,
   disabled = false,
   type = "button",
   className = "",
 }: ButtonWithoutImgProps) {
-  const [isHover, setIsHover] = useState(false);
-
-  const bg = toCssColor(isHover && hoverBgColorVar ? hoverBgColorVar : bgColorVar);
-  const border = toCssColor(isHover && hoverBorderColorVar ? hoverBorderColorVar : borderColorVar);
-  const textColor = toCssColor(isHover && hoverTextColorVar ? hoverTextColorVar : textColorVar);
+  const bg = toCssColor(bgColorVar);
+  const border = toCssColor(borderColorVar);
+  const textColor = toCssColor(textColorVar);
+  
+  const hoverBg = hoverBgColorVar ? toCssColor(hoverBgColorVar) : undefined;
+  const hoverBorder = hoverBorderColorVar ? toCssColor(hoverBorderColorVar) : undefined;
+  const hoverText = hoverTextColorVar ? toCssColor(hoverTextColorVar) : undefined;

   return (
     <button
       type={type}
       disabled={disabled}
       onClick={disabled ? undefined : onClick}
-      onMouseEnter={disabled ? undefined : () => setIsHover(true)}
-      onMouseLeave={disabled ? undefined : () => setIsHover(false)}
       style={{
+        '--bg-color': bg,
+        '--border-color': border,
+        '--text-color': textColor,
+        '--hover-bg-color': hoverBg || bg,
+        '--hover-border-color': hoverBorder || border,
+        '--hover-text-color': hoverText || textColor,
         width,
         height,
-        backgroundColor: bg,
-        borderColor: border,
-        color: textColor,
-      }}
+      } as React.CSSProperties}
       className={[
         "flex px-[16px] py-[12px] justify-center items-center gap-[10px]",
         "rounded-[8px] border",
         "Body_1_2 whitespace-nowrap",
+        "[background-color:var(--bg-color)] [border-color:var(--border-color)] [color:var(--text-color)]",
+        "hover:[background-color:var(--hover-bg-color)] hover:[border-color:var(--hover-border-color)] hover:[color:var(--hover-text-color)]",
         "transition-colors",
         disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
         className,
       ].join(" ")}
     >
       {text}
     </button>
   );
 }
src/components/base-ui/Settings/setting_report_list.tsx (2)

22-28: Consider responsive width instead of fixed pixel width.

The fixed w-[1000px] will cause horizontal overflow on smaller screens. Consider using w-full max-w-[1000px] to allow the component to adapt to narrower viewports.

๐Ÿ”Ž Proposed fix
     <div
       className={`
-        flex w-[1000px] p-[20px] items-start gap-[40px]
+        flex w-full max-w-[1000px] p-[20px] items-start gap-[40px]
         rounded-[8px] border border-[color:var(--Subbrown_4,#EAE5E2)]
         bg-[color:var(--White,#FFF)]
         ${className}
       `}
     >

46-46: Consider adding an avatar URL prop.

The hard-coded /profile5.svg avatar limits flexibility. Consider adding an optional avatarUrl prop to allow customization per reporter.

๐Ÿ”Ž Proposed enhancement

Update the props type:

 type SettingReportListProps = {
   badgeText: string;
   reporterName: string;
   reportedAt: string;
   content: string;
+  avatarUrl?: string;
   className?: string;
 };

Update the component:

 export default function Setting_ReportList({
   badgeText,
   reporterName,
   reportedAt,
   content,
+  avatarUrl = "/profile5.svg",
   className = "",
 }: SettingReportListProps) {
   // ...
-  <Image src="/profile5.svg" alt="" width={24} height={24} />
+  <Image src={avatarUrl} alt="" width={24} height={24} />
src/components/base-ui/Search/search_recommendbook.tsx (2)

5-15: Consider exporting the type for better reusability.

The BookCoverCardProps type is well-structured. However, exporting it would allow parent components, tests, or documentation to reference the type explicitly, improving type safety and developer experience.

๐Ÿ”Ž Optional: Export the type
-type BookCoverCardProps = {
+export type BookCoverCardProps = {
   imgUrl?: string;
   title: string;
   author: string;
 
   liked: boolean;
   onLikeChange: (next: boolean) => void;
 
   onCardClick?: () => void;
   className?: string;
 };

38-47: Consider adding an accessible label to the like button.

The like button functions correctly with proper event propagation handling. However, it lacks an aria-label or accessible text, which would improve screen reader support.

๐Ÿ”Ž Optional: Add aria-label for accessibility
       <button
         type="button"
+        aria-label={liked ? "Unlike this book" : "Like this book"}
         onClick={(e) => {
           e.stopPropagation();
           onLikeChange(!liked);
         }}
         className="w-[24px] h-[24px] shrink-0"
       >
         <Image src={liked ? "/red_heart.svg" : "/gray_heart.svg"} alt="" width={24} height={24} />
       </button>
๐Ÿ“œ Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between ad62f6f and e75da33.

โ›” Files ignored due to path filters (20)
  • package-lock.json is excluded by !**/package-lock.json
  • public/ArrowDown.svg is excluded by !**/*.svg
  • public/ArrowTop.svg is excluded by !**/*.svg
  • public/Edit_icon.svg is excluded by !**/*.svg
  • public/Setting_icon.svg is excluded by !**/*.svg
  • public/booksample.svg is excluded by !**/*.svg
  • public/gray_heart.svg is excluded by !**/*.svg
  • public/icon_plus.svg is excluded by !**/*.svg
  • public/logo.svg is excluded by !**/*.svg
  • public/logo2.svg is excluded by !**/*.svg
  • public/notification.svg is excluded by !**/*.svg
  • public/pencil_icon.svg is excluded by !**/*.svg
  • public/plus.svg is excluded by !**/*.svg
  • public/profile.svg is excluded by !**/*.svg
  • public/profile2.svg is excluded by !**/*.svg
  • public/profile3.svg is excluded by !**/*.svg
  • public/profile4.svg is excluded by !**/*.svg
  • public/profile5.svg is excluded by !**/*.svg
  • public/red_heart.svg is excluded by !**/*.svg
  • public/search.svg is excluded by !**/*.svg
๐Ÿ“’ Files selected for processing (27)
  • .github/ISSUE_TEMPLATE/custom.md
  • src/app/(main)/layout.tsx
  • src/app/(main)/page.tsx
  • src/app/(main)/ui-test/page.tsx
  • src/app/globals.css
  • src/app/layout.tsx
  • src/app/page.backup.tsx
  • src/components/base-ui/BookStory/bookstory_choosebook.tsx
  • src/components/base-ui/BookStory/bookstory_detail.tsx
  • src/components/base-ui/BookStory/bookstory_text.tsx
  • src/components/base-ui/News/news_list.tsx
  • src/components/base-ui/News/recommendbook_element.tsx
  • src/components/base-ui/Profile/mypage_profile.tsx
  • src/components/base-ui/Profile/notification_element.tsx
  • src/components/base-ui/Profile/others_profile.tsx
  • src/components/base-ui/Profile/subscribe_element.tsx
  • src/components/base-ui/Search/search_bookresult.tsx
  • src/components/base-ui/Search/search_recommendbook.tsx
  • src/components/base-ui/Settings/setting_news_list.tsx
  • src/components/base-ui/Settings/setting_report_list.tsx
  • src/components/base-ui/button_without_img.tsx
  • src/components/base-ui/home/home_bookclub.tsx
  • src/components/base-ui/home/list_subscribe_element.tsx
  • src/components/base-ui/home/notification_element.tsx
  • src/components/layout/Header.tsx
  • src/components/layout/NavItem.tsx
  • tsconfig.json
๐Ÿ’ค Files with no reviewable changes (1)
  • src/app/layout.tsx
๐Ÿงฐ Additional context used
๐Ÿงฌ Code graph analysis (3)
src/app/(main)/layout.tsx (1)
src/components/layout/Header.tsx (1)
  • Header (15-97)
src/components/layout/Header.tsx (1)
src/components/layout/NavItem.tsx (1)
  • NavItem (9-28)
src/app/(main)/ui-test/page.tsx (1)
src/components/base-ui/Settings/setting_report_list.tsx (1)
  • Setting_ReportList (14-65)
๐Ÿ”‡ Additional comments (28)
src/components/base-ui/Profile/subscribe_element.tsx (1)

1-55: LGTM!

The component is well-structured with proper TypeScript types, safe optional callback invocation via onToggleSubscribe?.(!isSubscribed), and correct usage of Next.js Image with fill and sizes. The conditional button styling based on subscription state is clear.

src/components/base-ui/Profile/others_profile.tsx (1)

6-118: LGTM overall!

The component structure is clean with proper TypeScript typing, correct Next.js Image usage with fill and sizes, and well-organized layout. The conditional styling for the subscribe button based on isSubscribed state is well-implemented.

src/components/base-ui/home/list_subscribe_element.tsx (1)

1-55: LGTM overall!

The component is well-structured with proper TypeScript types and correct Next.js Image usage. The layout and styling are consistent with other subscribe-related components in the PR.

src/components/base-ui/BookStory/bookstory_choosebook.tsx (3)

1-2: LGTM!

Imports are correct. The explicit React import is harmless and works fine with React 19's JSX transform.


4-11: LGTM!

The type definition is well-structured with appropriate field types and optional props for extensibility.


70-75: LGTM!

JSX structure is correctly balanced with all opening and closing tags properly matched.

.github/ISSUE_TEMPLATE/custom.md (1)

5-27: LGTM!

The issue template improvements add helpful guidance text and a new issue type option, making the template more user-friendly.

tsconfig.json (1)

38-39: LGTM!

The additions of .next/types/**/*.ts and .next/dev/types/**/*.ts properly support Next.js 16's generated type declarations, ensuring full TypeScript coverage for the framework-generated types.

src/components/base-ui/News/recommendbook_element.tsx (1)

26-56: LGTM!

The component implementation follows Next.js best practices:

  • Proper default fallback for missing images
  • Correct use of fill with explicit sizes for optimization
  • Event propagation correctly managed for nested click handlers
  • Text overflow handled appropriately with truncate and min-w-0
src/components/base-ui/BookStory/bookstory_detail.tsx (1)

40-107: LGTM!

The component follows Next.js and React best practices:

  • Proper default values for optional props
  • Correct Image usage with explicit parent dimensions and sizes
  • Meaningful alt attributes for accessibility
  • Proper text truncation with flex layout (min-w-0)
  • Link component used appropriately for navigation
src/app/globals.css (2)

4-33: LGTM!

The design token structure is well-organized with a comprehensive color palette. The custom property naming convention (using underscores) is consistent throughout the codebase and properly referenced by components.


52-52: LGTM!

The font family update to Pretendard with proper fallbacks provides excellent Korean typography support while maintaining system font fallbacks.

src/components/layout/NavItem.tsx (1)

1-7: LGTM!

The interface definition is clear and includes all necessary props for a navigation item component.

src/app/(main)/layout.tsx (1)

1-11: LGTM!

The layout implementation is clean and follows Next.js App Router conventions. It properly integrates the Header component and wraps children in a semantic <main> element.

src/app/(main)/ui-test/page.tsx (1)

10-18: LGTM!

The test page correctly demonstrates the Setting_ReportList component with intentionally long content to verify text wrapping and overflow behavior.

src/components/layout/Header.tsx (4)

1-7: LGTM!

The imports are appropriate, and the "use client" directive is correctly placed since the component uses the usePathname hook.


8-13: LGTM!

The navigation structure is well-defined with clear labels and corresponding routes.


36-39: Active state logic works but has a potential edge case.

The current logic uses pathname.startsWith(item.href) for non-root routes. This could cause issues if you add nested or similarly-named routes in the future (e.g., /groups and /groups-admin would both match when visiting /groups-admin).

Consider whether you need more precise matching in the future. For now, this works with the current route structure.


24-91: All required image assets are present in the public directory (logo.svg, search.svg, notification.svg, profile.svg). No 404 errors will occur from these assets.

src/components/base-ui/button_without_img.tsx (2)

25-31: LGTM: Color normalization helper.

The toCssColor helper correctly handles multiple color formats (CSS variables, -- prefixes, and raw values).


33-51: LGTM: Well-structured component props.

The component signature is clear, type-safe, and provides sensible defaults for colors and dimensions.

src/components/base-ui/Search/search_bookresult.tsx (3)

44-45: Verify remotePatterns for external book cover images.

The imgUrl prop can contain external URLs. Ensure your next.config.js includes appropriate remotePatterns for book cover image sources (e.g., book API domains).


35-43: LGTM: Card click handling.

The optional onCardClick handler and conditional cursor styling are implemented correctly.


61-91: LGTM: Button event handling with stopPropagation.

The like and pencil buttons correctly use stopPropagation() to prevent triggering the card's onCardClick handler. The optional onPencilClick is safely handled with optional chaining.

src/components/base-ui/Settings/setting_report_list.tsx (1)

14-20: LGTM: Clear component props definition.

The props are well-documented with inline comments showing expected formats, and the default className is handled appropriately.

src/components/base-ui/Search/search_recommendbook.tsx (3)

1-4: LGTM!

Correct setup for a client-side component with Next.js Image.


17-26: LGTM!

Component signature and fallback logic are correct. The coverSrc resolution properly handles missing or empty imgUrl values.


49-52: LGTM!

Text content rendering correctly follows the established CSS conventions (color tokens and typography classes) and includes proper overflow handling with truncate.

"use client";
import React from "react";
import { useState } from "react";
import Subscribe_elements from "@/components/base-ui/Profile/subscribe_element";
Copy link

Choose a reason for hiding this comment

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

๐Ÿ› ๏ธ Refactor suggestion | ๐ŸŸ  Major

Remove unused import and state.

The Subscribe_elements import and the subs state variable are declared but never used in the component.

๐Ÿ”Ž Remove unused code
 "use client";
 import React from "react";
-import { useState } from "react";
-import Subscribe_elements from "@/components/base-ui/Profile/subscribe_element";
 import Setting_ReportList from "@/components/base-ui/Settings/setting_report_list";

 export default function UiTestClient() {
-  const [subs, setSubs] = useState(false);
-
   return (
     <div className="h-[2000px] bg-gray-100 p-8">

If you plan to use these later for testing Subscribe_elements, keep them and add a comment explaining the future intent.

Also applies to: 8-8

๐Ÿค– Prompt for AI Agents
In src/app/(main)/ui-test/page.tsx around lines 4 and 8, the import
Subscribe_elements and the subs state variable are declared but unused; remove
the unused import line and the subs state declaration (or, if you intend to use
them later, keep both and add a clear comment explaining the future intent),
then run TypeScript/ESLint to ensure no remaining unused-symbol errors.

Comment on lines +57 to +59
.Headline_1 { @apply text-[48px] font-bold leading-[135%] tracking-[-0.1%]; }
.Headline_2 { @apply text-[36px] font-bold leading-[135%] tracking-[-0.1%]; }
.Headline_3 { @apply text-[32px] font-bold leading-[135%] tracking-[-0.1%]; }
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

Critical: Invalid tracking (letter-spacing) percentage values.

Lines 57-59 and 62-67 use tracking-[-0.1%], but the CSS letter-spacing property does not accept percentage valuesโ€”only length units (px, em, rem, etc.) are valid. These declarations will be ignored by browsers, causing the intended letter-spacing to not apply.

๐Ÿ”Ž Proposed fix

The value -0.1% likely intends -0.001em (which is roughly 0.1% of the font size). Update all instances:

  /* Headline */
- .Headline_1 { @apply text-[48px] font-bold leading-[135%] tracking-[-0.1%]; }
- .Headline_2 { @apply text-[36px] font-bold leading-[135%] tracking-[-0.1%]; }
- .Headline_3 { @apply text-[32px] font-bold leading-[135%] tracking-[-0.1%]; }
+ .Headline_1 { @apply text-[48px] font-bold leading-[135%] tracking-[-0.001em]; }
+ .Headline_2 { @apply text-[36px] font-bold leading-[135%] tracking-[-0.001em]; }
+ .Headline_3 { @apply text-[32px] font-bold leading-[135%] tracking-[-0.001em]; }

  /* Subhead */
- .Subhead_1 { @apply text-[24px] font-semibold leading-[135%] tracking-[-0.1%]; }
- .Subhead_2 { @apply text-[20px] font-semibold leading-[135%] tracking-[-0.1%]; }
- .Subhead_3_1 { @apply text-[18px] font-semibold leading-[135%] tracking-[-0.1%]; }
- .Subhead_3_2 { @apply text-[18px] font-medium leading-[135%] tracking-[-0.1%]; }
+ .Subhead_1 { @apply text-[24px] font-semibold leading-[135%] tracking-[-0.001em]; }
+ .Subhead_2 { @apply text-[20px] font-semibold leading-[135%] tracking-[-0.001em]; }
+ .Subhead_3_1 { @apply text-[18px] font-semibold leading-[135%] tracking-[-0.001em]; }
+ .Subhead_3_2 { @apply text-[18px] font-medium leading-[135%] tracking-[-0.001em]; }

Alternatively, verify the intended value from your design specifications and use the correct length unit.

Also applies to: 62-67

๐Ÿค– Prompt for AI Agents
In src/app/globals.css around lines 57-59 (and also lines 62-67), the classes
use tracking-[-0.1%], but letter-spacing does not accept percentage values;
replace each tracking-[-0.1%] with a proper length unit (e.g.,
tracking-[-0.001em] or tracking-[-0.1px] depending on design) so the rule is
applied, and update all instances across the file; verify with the design spec
and adjust the chosen unit/value accordingly.

Comment on lines +53 to +69
<button
type="button"
onClick={onButtonClick}
className="
flex w-[132px] h-[44px]
px-[16px] py-[12px]
justify-center items-center gap-[10px]
rounded-[8px]
border border-[color:var(--premary_2,#9A7A6B)]
bg-[color:var(--background,#F9F7F6)]
text-[color:var(--premary_2,#9A7A6B)]
Body_1_2
whitespace-nowrap
"
>
๋ณ€๊ฒฝํ•˜๊ธฐ
</button>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

Fix typo in CSS variable name: premary โ†’ primary.

The button has a typo in the CSS variable name on lines 61 and 63: --premary_2 should be --primary_2. This will cause the variable lookup to fail and fall back to the hardcoded hex color, breaking design system consistency and potentially causing styling issues if the variable is later defined correctly elsewhere.

๐Ÿ”Ž Proposed fix for the CSS variable typo
            className="
              flex w-[132px] h-[44px]
              px-[16px] py-[12px]
              justify-center items-center gap-[10px]
              rounded-[8px]
-             border border-[color:var(--premary_2,#9A7A6B)]
+             border border-[color:var(--primary_2,#9A7A6B)]
              bg-[color:var(--background,#F9F7F6)]
-             text-[color:var(--premary_2,#9A7A6B)]
+             text-[color:var(--primary_2,#9A7A6B)]
              Body_1_2
              whitespace-nowrap
            "
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
type="button"
onClick={onButtonClick}
className="
flex w-[132px] h-[44px]
px-[16px] py-[12px]
justify-center items-center gap-[10px]
rounded-[8px]
border border-[color:var(--premary_2,#9A7A6B)]
bg-[color:var(--background,#F9F7F6)]
text-[color:var(--premary_2,#9A7A6B)]
Body_1_2
whitespace-nowrap
"
>
๋ณ€๊ฒฝํ•˜๊ธฐ
</button>
<button
type="button"
onClick={onButtonClick}
className="
flex w-[132px] h-[44px]
px-[16px] py-[12px]
justify-center items-center gap-[10px]
rounded-[8px]
border border-[color:var(--primary_2,#9A7A6B)]
bg-[color:var(--background,#F9F7F6)]
text-[color:var(--primary_2,#9A7A6B)]
Body_1_2
whitespace-nowrap
"
>
๋ณ€๊ฒฝํ•˜๊ธฐ
</button>
๐Ÿค– Prompt for AI Agents
In src/components/base-ui/BookStory/bookstory_choosebook.tsx around lines 53 to
69, the button's CSS variable name contains a typo: replace all occurrences of
--premary_2 with --primary_2 (both in the border and text color usages) so the
component uses the correct design-system variable; update the className strings
accordingly and ensure no other instances of the misspelled variable remain in
the file.

Comment on lines +30 to +50
const handleDetailKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key !== "Tab") return;

e.preventDefault();

const el = e.currentTarget;
const start = el.selectionStart ?? 0;
const end = el.selectionEnd ?? 0;

const insert = " ";
const next = detail.slice(0, start) + insert + detail.slice(end);

onChangeDetail(next);

requestAnimationFrame(() => {
el.selectionStart = el.selectionEnd = start + insert.length;
});
},
[detail, onChangeDetail]
);
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐ŸŸ  Major

Tab key handling with controlled input may be unreliable.

Using requestAnimationFrame to restore cursor position after calling onChangeDetail is fragile. When onChangeDetail updates parent state, React re-renders this component and updates the textarea value, which can reset the cursor position unpredictablyโ€”potentially before or after your requestAnimationFrame callback runs.

A more robust approach is to track the desired cursor position in a ref and apply it in useLayoutEffect after the detail value changes.

๐Ÿ”Ž More reliable implementation
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
+ const cursorPosRef = useRef<number | null>(null);

  // โœ… ๋‚ด์šฉ์— ๋งž์ถฐ textarea ๋†’์ด ์ž๋™ ์กฐ์ ˆ
  useLayoutEffect(() => {
    const el = textareaRef.current;
    if (!el) return;

    el.style.height = "0px";
    el.style.height = `${el.scrollHeight}px`;
+
+   // Restore cursor position if pending
+   if (cursorPosRef.current !== null) {
+     el.selectionStart = el.selectionEnd = cursorPosRef.current;
+     cursorPosRef.current = null;
+   }
  }, [detail]);

  // textarea์—์„œ Tab์„ "๋“ค์—ฌ์“ฐ๊ธฐ"๋กœ ์ฒ˜๋ฆฌ
  const handleDetailKeyDown = useCallback(
    (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
      if (e.key !== "Tab") return;

      e.preventDefault();

      const el = e.currentTarget;
      const start = el.selectionStart ?? 0;
      const end = el.selectionEnd ?? 0;

      const insert = "  ";
      const next = detail.slice(0, start) + insert + detail.slice(end);

+     // Store desired cursor position
+     cursorPosRef.current = start + insert.length;
      onChangeDetail(next);
-
-     requestAnimationFrame(() => {
-       el.selectionStart = el.selectionEnd = start + insert.length;
-     });
    },
    [detail, onChangeDetail]
  );

Committable suggestion skipped: line range outside the PR's diff.

๐Ÿค– Prompt for AI Agents
In src/components/base-ui/BookStory/bookstory_text.tsx around lines 30-50, the
Tab key handler uses requestAnimationFrame to restore the textarea cursor which
is fragile with controlled inputs; instead, store the desired cursor position in
a ref inside the handler (set a ref to start + insert.length), call
onChangeDetail as before, remove the requestAnimationFrame, and then in a
useLayoutEffect that watches the detail value, if the ref has a stored position
set the textarea selectionStart/selectionEnd to that value and clear the ref;
ensure the textarea element is referenced via a ref accessible to
useLayoutEffect and keep dependencies minimal to avoid extra renders.

Comment on lines +1 to +4
"use client";

import React from "react";
import Image from "next/image";
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

find . -maxdepth 2 -name "package.json" -type f | head -5

Repository: checkmo2025/FE

Length of output: 72


๐Ÿ Script executed:

cat package.json | grep -A 5 '"dependencies"' | head -20

Repository: checkmo2025/FE

Length of output: 176


๐Ÿ Script executed:

cat -n src/components/base-ui/Profile/mypage_profile.tsx | head -50

Repository: checkmo2025/FE

Length of output: 1511


๐ŸŒ Web query:

Next.js 16.0.1 release date features compatibility

๐Ÿ’ก Result:

  • Release date: Next.js 16.0.1 was published in late October 2025 (stable 16.0.1 listed 2025-10-28). [1][2]

  • Notable features / highlights in the Next.js 16.x line (present in 16.0.x):

    • Cache Components / "use cache" + Partial Pre-Rendering improvements. [3]
    • Turbopack stable and default bundler (big dev/build perf gains). [3]
    • React upgrades (React 19.x integration and related new APIs). [3]
    • Routing, caching API updates (new refresh/updateTag/revalidateTag semantics) and Build Adapters API (alpha). [3]
    • Several breaking changes (async route params, image defaults, changes to App Router behavior). [3]
  • Compatibility / ecosystem notes:

    • Many ecosystem packages needed updates for Next 16; some libraries (auth SDKs, adapters, etc.) reported peer-dependency conflicts with [email protected] โ€” expect to need updated versions or to use --legacy-peer-deps temporarily. [2][4]
    • Several security vulnerabilities affecting early 16.x releases were disclosed in Dec 2025; upgrading to later 16.x security patches (e.g., 16.0.7+ / 16.1.x) was recommended. If you run 16.0.1, check for patched 16.x releases. [5][1]

If you want, I can: (a) fetch the exact GitHub/npm release entries for v16.0.1, (b) list breaking-change upgrade steps, or (c) check a specific thirdโ€‘party package for Next 16 compatibility.


๐ŸŒ Web query:

React 19.2.0 release date stability

๐Ÿ’ก Result:

React 19.2.0 (stable) was released October 1, 2025. [1]

Notes on stability:

  • The React team published 19.2 as a stable release on the official React blog. [1]
  • Prior to the stable release there were multiple 19.2.0-canary builds published to npm (canary = prerelease). Use the stable tag ([email protected]) from the official release rather than canary builds for production. [2][3][4]

Upgrade Next.js from 16.0.1 to 16.0.7 or later due to security vulnerabilities.

React 19.2.0 is stable and all features used ("use client" directive, Image component with fill prop, React patterns) are fully supported in these versions. However, Next.js 16.0.1 has known security vulnerabilities disclosed in December 2025. Upgrade to Next.js 16.0.7 or 16.1.x to receive security patches. Also verify that ecosystem dependencies (auth SDKs, adapters, etc.) are compatible with Next.js 16, as some packages reported peer-dependency conflicts requiring --legacy-peer-deps or updated versions.

๐Ÿค– Prompt for AI Agents
In src/components/base-ui/Profile/mypage_profile.tsx (lines 1-4): the project is
using Next.js 16.0.1 which has known security vulnerabilities; update the
Next.js dependency in package.json to 16.0.7 or a later 16.x (or 16.1.x) safe
release, run a fresh install to update the lockfile (npm/yarn/pnpm), resolve or
update any peer-dependency conflicts for auth SDKs/adapters (upgrade those
packages or use appropriate install flags only as a last resort), run the test
suite and a local build to catch runtime/API changes, and commit the updated
package.json and lockfile once compatibility is confirmed.

<div className="flex items-start">
<div className="py-[9px] pr-[36px] shrink-0">
<div className="relative w-[138px] h-[138px] overflow-hidden rounded-full">
<Image src={profileImgSrc} alt={name} fill className="object-cover" sizes="138px" />
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

#!/bin/bash
# First, check for the existence of image assets referenced in the component
echo "=== Checking for image assets in public directory ==="
for asset in profile3.svg Edit_icon.svg setting_icon.svg; do
  if fd -t f "^${asset}$" public 2>/dev/null; then
    echo "โœ“ Found: $asset"
  else
    echo "โœ— Missing: $asset"
  fi
done

# Also check what files exist in the public directory for reference
echo ""
echo "=== All files in public directory ==="
fd -t f . public 2>/dev/null | head -20

Repository: checkmo2025/FE

Length of output: 681


๐Ÿ Script executed:

#!/bin/bash
# Inspect the file at the specified lines to see what images are referenced
echo "=== Checking lines 47, 92, 101 in mypage_profile.tsx ==="
sed -n '45,49p; 90,94p; 99,103p' src/components/base-ui/Profile/mypage_profile.tsx

Repository: checkmo2025/FE

Length of output: 843


Fix filename case mismatch at line 101.

The image reference at line 101 uses /setting_icon.svg (lowercase), but the actual file in the public directory is Setting_icon.svg (capital S). On case-sensitive filesystems, this will cause the image to fail loading. Update the reference to /Setting_icon.svg to match the actual filename.

Line 92's reference to /Edit_icon.svg is correct. Line 47 uses a dynamic source variable and does not directly reference a static asset.

๐Ÿค– Prompt for AI Agents
In src/components/base-ui/Profile/mypage_profile.tsx around line 101, the image
src references "/setting_icon.svg" which mismatches the actual public file
"Setting_icon.svg" (capital S); update the import string to "/Setting_icon.svg"
so the filename case matches exactly on case-sensitive filesystems and leave the
"/Edit_icon.svg" and dynamic profile image usage unchanged.

<div className="flex-1 min-w-0">
<div className="flex items-start justify-between">
<div className="min-w-0">
<p className="text-[color:var(--Gray_7,#2C2C2C)] Subhead_1 truncate">{name}</p>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

#!/bin/bash
# First, let's look for CSS/SCSS files and check for these class definitions
echo "=== Searching for custom typography class definitions ==="
rg -t css -t scss "Subhead_1|Subhead_4_1|Subhead_4|Body_1_2" --no-heading -C 1

echo ""
echo "=== Checking for Tailwind config or alternative CSS approach ==="
fd -t f -e "\.config\." -e "globals\." -e "tailwind\." | head -20

Repository: checkmo2025/FE

Length of output: 227


๐Ÿ Script executed:

#!/bin/bash
# Let's examine the target file to see the usage pattern
echo "=== Examining mypage_profile.tsx ==="
head -100 src/components/base-ui/Profile/mypage_profile.tsx | tail -50

echo ""
echo "=== Checking specific lines (54, 59, 65, 75, 93) ==="
sed -n '54p;59p;65p;75p;93p' src/components/base-ui/Profile/mypage_profile.tsx

Repository: checkmo2025/FE

Length of output: 2541


๐Ÿ Script executed:

#!/bin/bash
# Search for where these classes might be defined more broadly
echo "=== Searching all files for class definitions ==="
rg "Subhead_1|Subhead_4_1|Subhead_4|Body_1_2" --no-heading -l | head -20

Repository: checkmo2025/FE

Length of output: 958


๐Ÿ Script executed:

#!/bin/bash
# Check the globals.css file
echo "=== Checking src/app/globals.css ==="
cat src/app/globals.css

Repository: checkmo2025/FE

Length of output: 2654


Add missing .Subhead_4 typography class definition.

Three custom typography classes are properly defined in src/app/globals.css (Subhead_1, Subhead_4_1, Body_1_2), but .Subhead_4 is missing. This class is used at line 93 but has no corresponding definition in the utilities layer. Add the definition to globals.css or replace with an existing class like Subhead_4_1.

๐Ÿค– Prompt for AI Agents
In src/components/base-ui/Profile/mypage_profile.tsx around line 54 (and note
.Subhead_4 is used at line 93), the component references a non-existent
.Subhead_4 typography class; add a .Subhead_4 rule to src/app/globals.css in the
utilities layer (mirroring the existing Subhead_4_1 styles) or replace the usage
in mypage_profile.tsx with the existing Subhead_4_1 class to restore consistent
typography.

Comment on lines +100 to +102
<button type="button" onClick={onSettings} className="w-[24px] h-[24px] ">
<Image src="/setting_icon.svg" alt="" width={24} height={24} className="" />
</button>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐ŸŸ  Major

Add accessible label to icon-only settings button.

The settings button contains only an icon with no text label or aria-label, making it inaccessible to screen reader users. Add an aria-label attribute to describe the button's purpose.

๐Ÿ”Ž Add aria-label
-              <button type="button" onClick={onSettings} className="w-[24px] h-[24px] ">
+              <button type="button" onClick={onSettings} aria-label="์„ค์ • ์—ด๊ธฐ" className="w-[24px] h-[24px] ">
                 <Image src="/setting_icon.svg" alt="" width={24} height={24} className="" />
               </button>
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button type="button" onClick={onSettings} className="w-[24px] h-[24px] ">
<Image src="/setting_icon.svg" alt="" width={24} height={24} className="" />
</button>
<button type="button" onClick={onSettings} aria-label="์„ค์ • ์—ด๊ธฐ" className="w-[24px] h-[24px] ">
<Image src="/setting_icon.svg" alt="" width={24} height={24} className="" />
</button>
๐Ÿค– Prompt for AI Agents
In src/components/base-ui/Profile/mypage_profile.tsx around lines 100 to 102,
the settings button is icon-only and lacks an accessible name; add an aria-label
(e.g., aria-label="Open settings" or a localized equivalent) to the <button> so
screen readers can describe its purpose, ensuring the attribute is concise and
matches the button's action.

Comment on lines +1 to +55
"use client";
import Image from "next/image";

type NewsListProps = {
imageUrl: string;
title: string;
content: string;
date: string; // "2025-10-09" ๊ฐ™์€ ๋ฌธ์ž์—ด
className?: string;
};

export default function Setting_NewsList({
imageUrl,
title,
content,
date,
className = "",
}: NewsListProps) {
return (
<div
className={[
"inline-flex w-full max-w-[1000px] p-[20px] items-start",
"rounded-[8px] border border-[color:var(--Subbrown_4,#EAE5E2)] bg-white gap-6",
className,
].join(" ")}
>
{/* left image */}
<div className="relative w-[100px] h-[145px] shrink-0 ">
<Image
src={imageUrl}
alt={title}
fill
sizes="100px"
className="object-cover"
/>
</div>

{/* middle + right */}
<div className="flex flex-1 min-w-0 items-start">
{/* middle text */}
<div className="flex flex-col gap-[8px] min-w-0 flex-1">
<p className="text-[#000] Subhead_3 truncate">{title}</p>
<p className="text-[color:var(--Gray_4,#8D8D8D)] Body_1_2 line-clamp-6">
{content}
</p>
</div>

{/* ์ตœ์†Œ 120px ํ™•๋ณด + ๋‚ ์งœ ์˜ค๋ฅธ์ชฝ ๊ณ ์ • */}
<div className="shrink-0 min-w-[180px] text-right">
<p className="text-[color:var(--Gray_3,#BBB)] Body_1_2">{date}</p>
</div>
</div>
</div>
);
}
Copy link

Choose a reason for hiding this comment

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

๐Ÿ› ๏ธ Refactor suggestion | ๐ŸŸ  Major

Extract shared component to eliminate duplication.

This component is nearly identical to src/components/base-ui/News/news_list.tsx, differing only in max-w-[1000px] vs max-w-[1040px]. Consider extracting a shared base component that accepts maxWidth as a prop, then wrap it in domain-specific exports.

๐Ÿ”Ž Proposed refactor to extract shared component

Create a new shared component:

// src/components/base-ui/shared/BaseNewsList.tsx
"use client";
import Image from "next/image";

type BaseNewsListProps = {
  imageUrl: string;
  title: string;
  content: string;
  date: string;
  maxWidth?: string;
  className?: string;
};

export default function BaseNewsList({
  imageUrl,
  title,
  content,
  date,
  maxWidth = "1040px",
  className = "",
}: BaseNewsListProps) {
  return (
    <div
      className={[
        `inline-flex w-full max-w-[${maxWidth}] p-[20px] items-start`,
        "rounded-[8px] border border-[color:var(--Subbrown_4,#EAE5E2)] bg-white gap-6",
        className,
      ].join(" ")}
    >
      {/* ... rest of implementation ... */}
    </div>
  );
}

Then update this file:

-"use client";
-import Image from "next/image";
-
-type NewsListProps = {
-  imageUrl: string;
-  title: string;
-  content: string;
-  date: string;
-  className?: string;
-};
-
-export default function Setting_NewsList({
-  imageUrl,
-  title,
-  content,
-  date,
-  className = "",
-}: NewsListProps) {
-  return (
-    <div className={[/* ... */].join(" ")}>
-      {/* ... */}
-    </div>
-  );
-}
+import BaseNewsList from "../shared/BaseNewsList";
+
+type NewsListProps = {
+  imageUrl: string;
+  title: string;
+  content: string;
+  date: string;
+  className?: string;
+};
+
+export default function Setting_NewsList(props: NewsListProps) {
+  return <BaseNewsList {...props} maxWidth="1000px" />;
+}

Committable suggestion skipped: line range outside the PR's diff.

๐Ÿค– Prompt for AI Agents
In src/components/base-ui/Settings/setting_news_list.tsx lines 1-55: the
component largely duplicates src/components/base-ui/News/news_list.tsx; extract
a shared BaseNewsList component (e.g.,
src/components/base-ui/shared/BaseNewsList.tsx) that contains the full markup
and accepts props for imageUrl, title, content, date and a maxWidthClass or
className prop to control the max-w utility (avoid building Tailwind classes
with string interpolationโ€”accept the full class like "max-w-[1000px]" or
"max-w-[1040px]" from the caller). Replace this file with a thin wrapper that
imports BaseNewsList and renders it with maxWidthClass="max-w-[1000px]" (and
similarly update the other news_list to pass "max-w-[1040px]"), forwarding any
className and props unchanged.

Comment on lines +29 to +35
<Image
src={imageUrl}
alt={title}
fill
sizes="100px"
className="object-cover"
/>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐ŸŸ  Major

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

# Find next.config files in the repository
fd -e js -e ts -e mjs -e cjs 'next\.config'

Repository: checkmo2025/FE

Length of output: 72


๐Ÿ Script executed:

# Examine the component file to understand the context
cat -n src/components/base-ui/Settings/setting_news_list.tsx | head -60

Repository: checkmo2025/FE

Length of output: 1845


๐Ÿ Script executed:

cat -n next.config.ts

Repository: checkmo2025/FE

Length of output: 269


Add remotePatterns configuration for external image URLs.

The Image component loads external URLs via the imageUrl prop, but next.config.ts lacks the required remotePatterns configuration. Without this, Next.js will throw a "hostname is not allowed" error at runtime.

Add remotePatterns to next.config.ts:

const nextConfig: NextConfig = {
  reactCompiler: true,
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**', // Adjust to specific domains for production
      },
    ],
  },
};

Replace the wildcard with specific hostnames you expect to load (e.g., example.com, cdn.example.com).

๐Ÿค– Prompt for AI Agents
In src/components/base-ui/Settings/setting_news_list.tsx lines 29-35 the Image
component uses external imageUrl values but next.config.ts lacks
images.remotePatterns, causing "hostname is not allowed" runtime errors; update
next.config.ts to add an images.remotePatterns array that allows the external
hosts (e.g., entries with protocol: 'https' and hostname: 'example.com' or
'cdn.example.com' or a '**' wildcard for dev), replace the wildcard with the
specific domains you expect for production, and restart the Next.js server so
the new image host rules take effect.

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.

5 participants