Skip to content
19 changes: 19 additions & 0 deletions public/assets/svg/bed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

const IconBed = ({ size = 24, color = '#112211', ...props }) => (
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

TypeScript 타입 정의 추가 필요

props 매개변수에 대한 적절한 TypeScript 인터페이스가 누락되었습니다. 타입 안전성을 위해 인터페이스를 정의해주세요.

다음과 같이 인터페이스를 추가하세요:

+interface IconBedProps extends React.SVGProps<SVGSVGElement> {
+  size?: number;
+  color?: string;
+}
+
-const IconBed = ({ size = 24, color = '#112211', ...props })  => (
+const IconBed: React.FC<IconBedProps> = ({ size = 24, color = '#112211', ...props }) => (
📝 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
const IconBed = ({ size = 24, color = '#112211', ...props }) => (
interface IconBedProps extends React.SVGProps<SVGSVGElement> {
size?: number;
color?: string;
}
const IconBed: React.FC<IconBedProps> = ({ size = 24, color = '#112211', ...props }) => (
/* existing SVG JSX */
);
🤖 Prompt for AI Agents
In public/assets/svg/bed.tsx at line 3, the props parameter lacks a TypeScript
interface definition, reducing type safety. Define an interface for the
component props specifying types for size, color, and any other props, then
apply this interface to the IconBed component's props parameter to ensure proper
type checking.

<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
fill={color}
viewBox="0 0 24 24"
{...props}
>
<path
fill={color}
d="M20.25 10.814a3.7 3.7 0 0 0-1.5-.314H5.25a3.754 3.754 0 0 0-3.75 3.75v5.25a.75.75 0 1 0 1.5 0v-.375a.38.38 0 0 1 .375-.375h17.25a.38.38 0 0 1 .375.375v.375a.75.75 0 1 0 1.5 0v-5.25a3.75 3.75 0 0 0-2.25-3.436M17.625 3.75H6.375A2.625 2.625 0 0 0 3.75 6.375V9.75a.187.187 0 0 0 .24.18c.409-.12.833-.18 1.26-.18h.198a.19.19 0 0 0 .188-.166A1.5 1.5 0 0 1 7.125 8.25H9.75a1.5 1.5 0 0 1 1.49 1.334.19.19 0 0 0 .188.166h1.147a.187.187 0 0 0 .187-.166A1.5 1.5 0 0 1 14.25 8.25h2.625a1.5 1.5 0 0 1 1.49 1.334.19.19 0 0 0 .188.166h.197c.427 0 .851.06 1.26.18a.188.188 0 0 0 .24-.18V6.375a2.625 2.625 0 0 0-2.625-2.625"
></path>
</svg>
);

export default IconBed;
34 changes: 34 additions & 0 deletions src/app/(with-header)/components/BannerSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Image from 'next/image';
import SearchBar from './SearchBar';

export default function BannerSection() {
return (
<section className="relative w-full h-240 md:h-550 mb-93">
{/* 배경 이미지 */}
<Image
src="/test/image1.png"
alt="스트릿 댄스"
fill
className="object-cover"
priority
/>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

하드코딩된 이미지 경로와 접근성 개선이 필요합니다.

현재 구현에서 몇 가지 개선점이 있습니다:

  1. /test/image1.png 경로가 하드코딩되어 있어 유지보수성이 떨어집니다
  2. alt 텍스트가 너무 간단합니다

다음과 같이 개선하는 것을 권장합니다:

-        src="/test/image1.png"
-        alt="스트릿 댄스"
+        src="/images/banner/street-dance-main.png"
+        alt="스트릿 댄스 강의 현장 모습 - 사람들이 함께 춤을 추고 있는 배경 이미지"
📝 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
<Image
src="/test/image1.png"
alt="스트릿 댄스"
fill
className="object-cover"
priority
/>
<Image
- src="/test/image1.png"
- alt="스트릿 댄스"
+ src="/images/banner/street-dance-main.png"
+ alt="스트릿 댄스 강의 현장 모습 - 사람들이 함께 춤을 추고 있는 배경 이미지"
fill
className="object-cover"
priority
/>
🤖 Prompt for AI Agents
In src/app/(with-header)/components/BannerSection.tsx around lines 8 to 14, the
image source path is hardcoded and the alt text is too simple, which affects
maintainability and accessibility. Refactor the code to use a dynamic or
imported image path instead of a hardcoded string, and enhance the alt attribute
to provide a more descriptive and meaningful text that improves accessibility
for screen readers.


{/* 어두운 오버레이 */}
<div className="absolute inset-0 bg-gradient-to-r from-black to-transparent" />

{/* 텍스트 콘텐츠 */}
<div className="relative z-10 flex flex-col items-start w-220 max-w-1152 md:w-440 lg:w-full pl-24 pt-74 md:pl-32 lg:pl-0 md:pt-144 lg:pt-159 lg:ml-auto lg:mr-auto gap-8 lg:gap-20 h-full text-white font-bold break-keep">
<h2 className="text-2xl md:text-[54px] md:leading-[64px] lg:text-[68px] lg:leading-[78px]">
함께 배우면 즐거운<br />
스트릿 댄스
</h2>
<p className="text-md md:text-xl lg:text-2xl">
1월의 인기 경험 BEST 🔥
</p>
</div>
<div className='absolute -bottom-100 left-0 right-0'>
<SearchBar />
</div>
</section>
);
}
48 changes: 48 additions & 0 deletions src/app/(with-header)/components/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client';

import { useState, FormEvent } from 'react';
import Input from '@components/Input';
import Button from '@components/Button';

export default function SearchBar() {
const [searchValue, setSearchValue] = useState('');

const handleSubmit = (e: FormEvent) => {
e.preventDefault();
console.log('검색어:', searchValue); // 검색 로직은 추후 API 연동
};

return (
<section className="flex lg:w-full lg:max-w-1152 lg:ml-auto lg:mr-auto justify-center px-16 lg:px-0">
<div className="flex flex-col w-full gap-15 md:gap-32 px-24 py-16 md:px-24 md:py-32 rounded-[16px] bg-white shadow-md">
<div className="flex items-start gap-2 mb-4">
<h3 className="text-lg md:text-xl font-bold text-left">
무엇을 체험하고 싶으신가요?
</h3>
</div>
<div className="text-center mb-6">
<form
onSubmit={handleSubmit}
className="flex flex-row gap-12 h-56"
>
<div className="relative flex-1">
<Input
type="text"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder="내가 원하는 체험은"
/>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

입력 필드 접근성 개선 제안

입력 필드에 적절한 label이나 aria-label이 누락되었습니다. 접근성 향상을 위해 추가해주세요.

다음과 같이 수정하세요:

            <div className="relative flex-1">
              <Input
                type="text"
                value={searchValue}
                onChange={(e) => setSearchValue(e.target.value)}
                placeholder="내가 원하는 체험은"
+               aria-label="체험 검색"
              />
            </div>
📝 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
<Input
type="text"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder="내가 원하는 체험은"
/>
<div className="relative flex-1">
<Input
type="text"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder="내가 원하는 체험은"
aria-label="체험 검색"
/>
</div>
🤖 Prompt for AI Agents
In src/app/(with-header)/components/SearchBar.tsx around lines 29 to 34, the
Input component lacks an accessible label or aria-label, which reduces
accessibility. Add an appropriate aria-label or associate a visible label with
the input field to improve screen reader support and overall accessibility.

</div>
<Button
type="submit"
variant="primary"
className="w-96 h-56 rounded-[4px] md:w-136 md:h-56"
>
검색하기
</Button>
</form>
</div>
</div>
</section>
);
}
16 changes: 9 additions & 7 deletions src/app/(with-header)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
// src/app/(with-header)/layout.tsx
import '@/app/globals.css';
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

글로벌 CSS import 위치 검증이 필요합니다.

레이아웃 컴포넌트에서 글로벌 CSS를 import하는 것이 적절한지 확인해야 합니다. 일반적으로 글로벌 CSS는 루트 레이아웃에서만 import되어야 합니다.

다음 스크립트를 실행하여 프로젝트에서 globals.css가 중복 import되고 있는지 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# 글로벌 CSS 중복 import 확인
echo "=== globals.css import 검색 ==="
rg -n "import.*globals\.css" --type tsx --type ts

echo "=== 루트 레이아웃 파일 확인 ==="
fd "layout.tsx" src/app --max-depth 1

Length of output: 258


글로벌 CSS가 루트 레이아웃에만 선언되어 있는지 확인해야 합니다. 아래 스크립트로 src/app/layout.tsx에서 globals.css import 여부를 확인해주세요.


🏁 Script executed:

#!/bin/bash
echo "=== 루트 레이아웃 globals.css import 확인 ==="
rg -n "import.*globals\.css" src/app/layout.tsx || echo "globals.css import 없음"

Length of output: 187


글로벌 CSS import 위치 조정 필요

프로젝트 전역 스타일이 src/app/(with-header)/layout.tsx에만 선언되어 있습니다. 글로벌 CSS는 오직 최상위 루트 레이아웃(src/app/layout.tsx)에서만 import되어야 하므로 아래와 같이 수정해주세요:

• src/app/(with-header)/layout.tsx

  • 2행의 import '@/app/globals.css'; 제거

• src/app/layout.tsx

  • 파일 최상단에 import '@/app/globals.css'; 추가
🤖 Prompt for AI Agents
In src/app/(with-header)/layout.tsx at line 2, remove the import statement for
'@/app/globals.css' because global CSS should only be imported once at the root
layout. Then, in src/app/layout.tsx, add the import statement for
'@/app/globals.css' at the very top of the file to ensure global styles are
applied project-wide correctly.

import Header from '@/components/Header';
import Footer from '@/components/Footer';

export default function Layout({ children }: { children: React.ReactNode }) {
export default function WithHeaderLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
{/* 공통 헤더 */}
{/* 헤더와 푸터 */}
<Header />

{/* 메인 콘텐츠 */}
<main className='min-h-screen pt-70'>{children}</main>

{/* 공통 푸터 */}
<main className="pt-70">{children}</main>
<Footer />
</>
);
Expand Down
9 changes: 9 additions & 0 deletions src/app/(with-header)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import BannerSection from '@/app/(with-header)/components/BannerSection';

export default function HomePage() {
return (
<main>
<BannerSection />
</main>
);
}
2 changes: 2 additions & 0 deletions src/app/page.tsx → src/app/icons/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import BedIcon from '@assets/svg/bed';
import BellIcon from '@assets/svg/bell';
import CheckIcon from '@assets/svg/check';
import ChevronIcon from '@assets/svg/chevron';
Expand All @@ -18,6 +19,7 @@ import IconYoutube from '@assets/svg/youtube';

export default function Home() {
const icons = [
{ name: 'BedIcon', component: <BedIcon size={32} /> },
{ name: 'BellIcon', component: <BellIcon size={32} /> },
{ name: 'CheckIcon', component: <CheckIcon size={32} /> },
{
Expand Down
16 changes: 6 additions & 10 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import './globals.css';
import QueryProvider from '@/lib/queryProvider';
export const metadata = {
title: 'GlobalNomad',
description: '글로벌 노마드 체험 플랫폼',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang='ko'>
<body>
<QueryProvider>
<main>{children}</main>
</QueryProvider>

<div id='modal-root' />
</body>
<html lang="ko">
<body>{children}</body>
</html>
);
}