Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"project": "./tsconfig.app.json"
},
"plugins": ["@typescript-eslint", "react", "react-hooks", "react-refresh", "check-file"],
"settings": {
Expand Down
6 changes: 2 additions & 4 deletions .github/ISSUE_TEMPLATE/bug-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,21 @@ about: 버그를 제보합니다.
title: 'fix: 이슈 제목'
labels: ''
assignees: ''

---

## 🐛 버그 설명


## 🔄 재현 방법

1.
2.
3.

## ✅ 예상 동작


## ❌ 실제 동작


## 💡 참고 사항 (Optional)

- 브라우저/환경:
- 스크린샷:
5 changes: 3 additions & 2 deletions .github/ISSUE_TEMPLATE/feature-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ about: 새로운 기능을 제안합니다.
title: 'type: 이슈 제목'
labels: ''
assignees: ''

---

## ✨ 구현할 기능


## 📝 TODO

- []
- []
- []

## 💡 참고 사항 (Optional)
4 changes: 3 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

## ✨ 변경 내용

어떤 기능/수정이 포함되었는지 간단 요약
-
-
-

## 💡 참고 사항

Expand Down
127 changes: 112 additions & 15 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,135 @@
# Copilot 코드 리뷰 지침

## 언어
> 한글로 리뷰해주세요

- 한글로 리뷰해주세요
---

## 기술 스택

- **Framework:** React 18 + TypeScript
- **Build:** Vite
- **Styling:** Tailwind CSS v4
- **Routing:** React Router

---

## 네이밍 컨벤션

- 폴더명: `kebab-case`
- 일반 파일(.ts): `camelCase`
- 컴포넌트 파일(.tsx): `PascalCase`
- 변수/함수명: `camelCase`
- 상수명: `UPPER_SNAKE_CASE`
- 컴포넌트명: `PascalCase`
- 페이지 컴포넌트: `PascalCase + Page` (예: `MainPage`)
| 대상 | 규칙 | 예시 |
| -------------------- | ------------------- | ----------------- |
| 폴더명 | `kebab-case` | `user-profile` |
| 일반 파일 (.ts) | `camelCase` | `useAuth.ts` |
| 컴포넌트 파일 (.tsx) | `PascalCase` | `UserCard.tsx` |
| 변수/함수명 | `camelCase` | `getUserName` |
| 상수명 | `UPPER_SNAKE_CASE` | `MAX_RETRY_COUNT` |
| 컴포넌트명 | `PascalCase` | `UserCard` |
| 페이지 컴포넌트 | `PascalCase + Page` | `MainPage` |
| 타입/인터페이스 | `PascalCase` | `UserProps` |

---

## 폴더 구조

```
src/
├── components/ # 재사용 컴포넌트
│ └── layout/ # 레이아웃 컴포넌트
├── constants/ # 상수
├── hooks/ # 커스텀 훅
├── pages/ # 페이지 컴포넌트
├── router/ # 라우터 설정
├── styles/ # 글로벌 스타일, 디자인 토큰
└── utils/ # 유틸 함수
```

---

## Export 규칙

- 컴포넌트: `export default`
- 유틸 함수: `named export`
- **컴포넌트:** `export function` (named export)
- **페이지:** `export default`
- **유틸 함수:** `named export`
- **타입:** `export type` / `export interface`

---

## 스타일링

### Tailwind CSS

- `style` 속성보다 Tailwind 유틸리티 클래스를 우선 사용해주세요
- 임의 값(`w-[35px]`) 사용을 지양하고, 테마에 정의된 값을 사용해주세요
- 색상은 디자인 시스템 팔레트를 사용해주세요 (`text-gray-600`, `bg-main`)

### 디자인 토큰

```css
/* 색상 */
--color-main, --color-gray-{100-900}, --color-error, --color-success

/* 타이포그래피 */
.text-body-m, .text-body-s, .text-caption
```

### 단위

- `px` 대신 `rem`을 사용해주세요

---

## React

### 컴포넌트

- Props는 `interface`로 정의해주세요
- 비즈니스 로직(Custom Hooks)과 UI(Component)를 분리해주세요

### Hooks

- `useEffect` 의존성 배열이 올바른지 확인해주세요
- 불필요한 리렌더링이 발생할 수 있는 코드인지 확인해주세요

### 라우팅

- `<a>` 태그 대신 `<Link>` 또는 `useNavigate`를 사용해주세요 (SPA 동작 보장)

---

## 코드 품질

- 불필요한 `console.log`가 있는지 확인해주세요
- 사용하지 않는 import가 있는지 확인해주세요
- TypeScript 타입이 `any`로 되어있는지 확인해주세요
- 하드코딩된 값이 상수로 분리되어야 하는지 확인해주세요
- 매직 넘버는 의미 있는 상수명으로 분리해주세요

## React
---

- 컴포넌트 props는 interface로 정의해주세요
- useEffect 의존성 배열이 올바른지 확인해주세요
- 불필요한 리렌더링이 발생할 수 있는 코드인지 확인해주세요
## 접근성 (Accessibility)

- 의미 없는 `<div>` 대신 시맨틱 태그를 적극 사용해주세요
- 모든 이미지(`<img>`)에는 적절한 `alt` 텍스트를 제공해주세요
- 버튼과 링크는 명확한 레이블을 가져야 합니다
- `role`, `aria-*` 속성을 적절히 사용해주세요

---

## 보안

- API 키나 민감한 정보가 하드코딩되어 있는지 확인해주세요
- 환경변수는 `VITE_` 접두사를 사용해야 합니다

---

## Git 커밋 컨벤션

```
<type>: <subject> (#issue)

feat: 새로운 기능
fix: 버그 수정
refactor: 리팩토링
style: 코드 포맷팅
chore: 기타 작업
docs: 문서 수정
```
7 changes: 6 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ttorang-frontend</title>
<title>또랑</title>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"
/>
</head>
<body>
<div id="root"></div>
Expand Down
33 changes: 33 additions & 0 deletions src/components/layout/GNB.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { TABS, type Tab } from '../../constants/navigation';

interface GNBProps {
activeTab?: Tab;
onTabChange?: (tab: Tab) => void;
}

export function GNB({ activeTab = 'slide', onTabChange }: GNBProps) {
return (
<nav
className="absolute left-1/2 flex h-15 -translate-x-1/2 items-center justify-center"
role="tablist"
>
{TABS.map(({ key, label }) => {
const isActive = activeTab === key;
return (
<button
key={key}
type="button"
role="tab"
aria-selected={isActive}
onClick={() => onTabChange?.(key)}
className={`flex h-full w-25 items-end justify-center px-2.5 pb-4 pt-4 text-body-m-bold border-b-2 ${
isActive ? 'border-main text-main' : 'border-transparent text-gray-600'
}`}
>
{label}
</button>
);
})}
</nav>
);
}
13 changes: 13 additions & 0 deletions src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ReactNode } from 'react';

interface HeaderProps {
children?: ReactNode;
}

export function Header({ children }: HeaderProps) {
return (
<header className="fixed top-0 left-0 right-0 z-50 flex h-15 items-center justify-center border-b border-gray-200 bg-white px-18">
{children}
</header>
);
}
17 changes: 17 additions & 0 deletions src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { ReactNode } from 'react';

import { Header } from './Header';

interface LayoutProps {
header: ReactNode;
children?: ReactNode;
}

export function Layout({ children, header }: LayoutProps) {
return (
<div className="min-h-screen bg-gray-100">
<Header>{header}</Header>
<main className="pt-15">{children}</main>
</div>
);
}
4 changes: 4 additions & 0 deletions src/components/layout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { GNB } from './GNB';
export { Header } from './Header';
export { Layout } from './Layout';
export { type Tab } from '../../constants/navigation';
7 changes: 7 additions & 0 deletions src/constants/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type Tab = 'slide' | 'video' | 'insight';

export const TABS: { key: Tab; label: string }[] = [
{ key: 'slide', label: '슬라이드' },
{ key: 'video', label: '영상' },
{ key: 'insight', label: '인사이트' },
];
1 change: 0 additions & 1 deletion src/styles/fonts.css

This file was deleted.

1 change: 0 additions & 1 deletion src/styles/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@import "tailwindcss";
@import "./fonts.css";
@import "./theme.css";
@import "./typography.css";

Expand Down
Loading