Skip to content

Feat 10#12

Closed
hongik-luke wants to merge 16 commits intomainfrom
feat-10
Closed

Feat 10#12
hongik-luke wants to merge 16 commits intomainfrom
feat-10

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.tsxmax-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: premaryprimary.

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.

@hongik-luke hongik-luke deleted the feat-10 branch February 6, 2026 19:39
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.

4 participants