Skip to content

Commit 0579038

Browse files
authored
Merge pull request #60 from prgrms-aibe-devcourse/refactor/59-nav-footer-reconstruct
[Refactor] 공통 네비게이션 및 푸터 정보 구조 정리
2 parents 1e5043b + bd2aa23 commit 0579038

4 files changed

Lines changed: 191 additions & 101 deletions

File tree

.claude/launch.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": "0.0.1",
3+
"configurations": [
4+
{
5+
"name": "codedock-dev",
6+
"runtimeExecutable": "npm",
7+
"runtimeArgs": ["run", "dev"],
8+
"port": 5173
9+
}
10+
]
11+
}

README.md

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,111 @@
1+
# CodeDock
12

2-
# 안씨네 머슴들 - 수정본
3+
> 코드가 안전하게 출항하는 곳, CodeDock
34
4-
This is a code bundle for 안씨네 머슴들 - 수정본. The original project is available at https://www.figma.com/design/UjIbte4ow5gEtST62Zn5gx/%EC%95%88%EC%94%A8%EB%84%A4-%EB%A8%B8%EC%8A%B4%EB%93%A4---%EC%88%98%EC%A0%95%EB%B3%B8.
5+
CodeDock은 PR 리뷰, 보안 점검, API 문서화, ERD 관리, 팀 채팅을 하나의 흐름으로 연결하는 AI 개발 워크플로우 플랫폼입니다.
6+
팀원이 코드 변경의 맥락을 빠르게 파악하고, 리뷰와 문서 작업을 같은 워크스페이스 안에서 이어갈 수 있도록 돕습니다.
57

6-
## Running the code
8+
<p>
9+
<img alt="React" src="https://img.shields.io/badge/React-18.3.1-61DAFB?style=flat-square&logo=react&logoColor=061015" />
10+
<img alt="Vite" src="https://img.shields.io/badge/Vite-6.3.5-646CFF?style=flat-square&logo=vite&logoColor=white" />
11+
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-TSX-3178C6?style=flat-square&logo=typescript&logoColor=white" />
12+
<img alt="Tailwind CSS" src="https://img.shields.io/badge/Tailwind_CSS-4.x-38BDF8?style=flat-square&logo=tailwindcss&logoColor=061015" />
13+
</p>
714

8-
Run `npm i` to install the dependencies.
15+
## 주요 기능
16+
17+
| 영역 | 설명 |
18+
| --- | --- |
19+
| 랜딩 / 인증 | CodeDock 브랜딩, 채팅형 로그인/회원가입, 테마/언어 전환 |
20+
| 대시보드 | 팀과 리포지토리 기준의 리뷰 현황, 위험 신호, 최근 활동 확인 |
21+
| 워크스페이스 | 채널 기반 협업, 팀 채팅, 리포지토리별 작업 공간 |
22+
| PR 리뷰 | PR 목록, AI 리뷰 요약, Diff 확인, 라인 코멘트와 스레드 |
23+
| API 명세 | Swagger UI 기반 API 명세 확인 |
24+
| ERD | Mermaid 기반 ERD 작성, 미리보기, 확대/축소, 다운로드 |
25+
| 문서 | PR 리뷰 요약, API 변경 명세, ERD 변경 기록 등 템플릿 기반 문서 작성 |
26+
| 프로필 / 설정 | 사용자 프로필, GitHub 연동 관리, 테마 설정 |
27+
28+
## 기술 스택
29+
30+
| 분류 | 사용 기술 |
31+
| --- | --- |
32+
| Core | React, TypeScript, Vite |
33+
| Routing | React Router |
34+
| UI | Tailwind CSS, Radix UI, lucide-react |
35+
| Animation | motion |
36+
| Diagram / Docs | Mermaid, Swagger UI |
37+
| Interaction | react-dnd, resizable panels |
38+
39+
## 시작하기
40+
41+
### 요구 환경
42+
43+
- Node.js 18 이상 권장
44+
- npm
45+
46+
### 설치
47+
48+
```bash
49+
npm install
50+
```
51+
52+
### 개발 서버 실행
53+
54+
```bash
55+
npm run dev
56+
```
57+
58+
또는:
59+
60+
```bash
61+
npm start
62+
```
63+
64+
기본 Vite 주소는 `http://localhost:5173` 입니다.
65+
66+
### 빌드
67+
68+
```bash
69+
npm run build
70+
```
71+
72+
## 주요 라우트
73+
74+
| Route | 화면 |
75+
| --- | --- |
76+
| `/` | 랜딩 페이지 |
77+
| `/login` | 로그인 |
78+
| `/signup` | 회원가입 |
79+
| `/workspace` | 대시보드 |
80+
| `/chat` | 워크스페이스 / 팀 채팅 |
81+
| `/prs` | PR 목록 |
82+
| `/pr/:id` | PR 리뷰 룸 |
83+
| `/api-spec` | API 명세 |
84+
| `/erd` | ERD |
85+
| `/docs` | 문서 |
86+
| `/profile` | 프로필 |
87+
| `/settings` | 설정 |
88+
89+
## 프로젝트 구조
90+
91+
```text
92+
src/
93+
app/
94+
components/ # 공통 UI, 레이아웃, 채팅/리뷰 패널
95+
contexts/ # 테마, 언어 컨텍스트
96+
pages/ # 라우트 단위 페이지
97+
i18n/ # 다국어 번역 데이터
98+
styles/ # 전역 스타일, 테마, 폰트
99+
```
100+
101+
## 협업 규칙
102+
103+
- 이슈 단위로 브랜치를 생성합니다.
104+
- 커밋 메시지는 `feat:`, `fix:`, `refactor:`, `docs:`, `chore:` 등의 prefix를 사용합니다.
105+
- PR은 최소 1명 이상의 리뷰 승인을 받은 뒤 병합합니다.
106+
- 로컬 설정 파일, 빌드 결과물, 로그 파일은 커밋하지 않습니다.
107+
108+
##
109+
110+
AIBE5 Final Project Team 1 Frontend
9111

10-
Run `npm run dev` to start the development server.
11-

src/app/components/Footer.tsx

Lines changed: 64 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,56 @@
1-
import { Github, Heart, Linkedin, Mail, Twitter } from "lucide-react";
1+
import { Github, Heart, Mail } from "lucide-react";
22
import { Link } from "react-router";
33
import { CodeDockWordmark } from "./CodeDockWordmark";
44
import { CoffeeLogo } from "./CoffeeLogo";
55
import { useLanguage } from "../contexts/LanguageContext";
66
import { useTheme } from "../contexts/ThemeContext";
77

88
const footerLinks = {
9-
product: [
10-
{ ko: "기능", en: "Features", path: "/#features" },
11-
{ ko: "대시보드", en: "Dashboard", path: "/workspace" },
12-
{ ko: "PR 리뷰", en: "PR Review", path: "/prs" },
9+
navigation: [
10+
{ ko: "팀 대시보드", en: "Team Dashboard", path: "/workspace" },
11+
{ ko: "협업 워크스페이스", en: "Collaboration Workspace", path: "/chat" },
1312
{ ko: "API 명세", en: "API Spec", path: "/api-spec" },
1413
{ ko: "ERD", en: "ERD", path: "/erd" },
1514
{ ko: "문서", en: "Docs", path: "/docs" }
1615
],
17-
company: [
18-
{ ko: "소개", en: "About", path: "/about" },
19-
{ ko: "소식", en: "Blog", path: "/blog" },
20-
{ ko: "채용", en: "Careers", path: "/careers" },
21-
{ ko: "문의", en: "Contact", path: "/contact" }
22-
],
23-
resources: [
24-
{ ko: "문서", en: "Documentation", path: "/docs" },
25-
{ ko: "API 참조", en: "API Reference", path: "/api-spec" },
26-
{ ko: "튜토리얼", en: "Tutorials", path: "/tutorials" },
27-
{ ko: "커뮤니티", en: "Community", path: "/community" }
28-
],
29-
legal: [
30-
{ ko: "개인정보", en: "Privacy", path: "/privacy" },
31-
{ ko: "이용약관", en: "Terms", path: "/terms" },
32-
{ ko: "보안", en: "Security", path: "/security" },
33-
{ ko: "쿠키", en: "Cookies", path: "/cookies" }
16+
account: [
17+
{ ko: "프로필", en: "Profile", path: "/profile" },
18+
{ ko: "설정", en: "Settings", path: "/settings" }
3419
]
3520
};
3621

3722
const socialLinks = [
38-
{ icon: Github, href: "https://github.com", label: "GitHub" },
39-
{ icon: Twitter, href: "https://twitter.com", label: "Twitter" },
40-
{ icon: Linkedin, href: "https://linkedin.com", label: "LinkedIn" },
41-
{ icon: Mail, href: "mailto:contact@coffeeting.dev", label: "Email" }
23+
{ icon: Github, href: "https://github.com/prgrms-aibe-devcourse/AIBE5_FinalProject_Team1_FE", label: "GitHub" },
24+
{ icon: Mail, href: "mailto:contact@codedock.dev", label: "Email" }
4225
];
4326

4427
export function Footer() {
4528
const currentYear = new Date().getFullYear();
4629
const { colors } = useTheme();
4730
const { language } = useLanguage();
4831
const isKorean = language === "ko";
32+
const tone = (alpha: number) => `${colors.primary}, ${alpha})`;
4933
const copy = {
50-
product: isKorean ? "제품" : "Product",
51-
company: isKorean ? "회사" : "Company",
52-
resources: isKorean ? "자료" : "Resources",
53-
legal: isKorean ? "정책" : "Legal",
34+
navigation: isKorean ? "메뉴" : "Menu",
35+
account: isKorean ? "계정" : "Account",
5436
description: isKorean
55-
? "AI 기반 개발 협업 플랫폼. 코딩은 개발자가, 리뷰와 문서는 AI가 돕습니다."
37+
? "PR 리뷰, 보안 점검, 문서화를 한 흐름으로 연결하는 AI 개발 워크스페이스입니다."
5638
: "An AI development workflow platform for reviews, docs, and team collaboration.",
57-
madeBy: isKorean ? "DevFlow Team 제작" : "by DevFlow Team",
39+
madeBy: "CodeDock Team",
5840
rights: isKorean ? "모든 권리 보유." : "All rights reserved.",
59-
madeWith: isKorean ? "제작" : "Made with"
41+
madeWith: "Made with"
6042
};
6143

62-
const renderLinks = (links: typeof footerLinks.product) => (
63-
<ul className="m-0 grid list-none gap-3 p-0">
44+
const renderLinks = (links: typeof footerLinks.navigation) => (
45+
<ul className="m-0 grid list-none gap-2 p-0">
6446
{links.map((link) => (
6547
<li key={link.path}>
6648
<Link
6749
to={link.path}
68-
className="no-underline tracking-tight transition-colors"
50+
className="no-underline tracking-tight transition-colors hover:text-white"
6951
style={{
70-
fontSize: "14px",
71-
fontWeight: 700,
52+
fontSize: "13px",
53+
fontWeight: 750,
7254
color: "var(--muted)"
7355
}}
7456
>
@@ -81,43 +63,46 @@ export function Footer() {
8163

8264
return (
8365
<footer
84-
className="relative mt-20"
66+
className="relative mt-12"
8567
style={{
8668
background: `
87-
radial-gradient(circle at 20% 50%, ${colors.primary}, 0.08), transparent 40%),
88-
radial-gradient(circle at 80% 50%, ${colors.primary}, 0.06), transparent 40%),
89-
rgba(5, 11, 20, 0.95)
69+
radial-gradient(circle at 18% 40%, ${tone(0.07)}, transparent 34%),
70+
radial-gradient(circle at 84% 54%, ${tone(0.05)}, transparent 36%),
71+
rgba(5, 11, 20, 0.94)
9072
`,
91-
borderTop: `1px solid ${colors.primary}, 0.15)`
73+
borderTop: `1px solid ${tone(0.14)}`
9274
}}
9375
>
94-
<div className="relative mx-auto w-[min(1400px,calc(100vw-36px))] px-6 py-16">
95-
<div className="mb-12 grid gap-12 md:grid-cols-2 lg:grid-cols-6">
96-
<div className="lg:col-span-2">
76+
<div className="relative mx-auto w-[min(1180px,calc(100vw-32px))] px-4 py-8 sm:px-6 sm:py-10">
77+
<div className="mb-7 grid gap-7 md:grid-cols-[minmax(0,1.5fr)_minmax(150px,0.5fr)_minmax(130px,0.45fr)]">
78+
<div>
9779
<Link
9880
to="/"
99-
className="mb-6 flex items-center gap-3 no-underline tracking-[-0.07em]"
81+
className="mb-3 flex items-center gap-3 no-underline tracking-[-0.07em]"
10082
style={{
10183
fontWeight: 950,
102-
fontSize: "30px",
84+
fontSize: "24px",
10385
color: "var(--white)"
10486
}}
10587
>
10688
<CoffeeLogo
107-
className="h-16 w-16 flex-shrink-0"
108-
style={{ filter: `drop-shadow(0 0 14px ${colors.primary}, 0.3))` }}
89+
className="h-12 w-12 flex-shrink-0"
90+
style={{ filter: `drop-shadow(0 0 14px ${tone(0.3)})` }}
10991
/>
11092
<CodeDockWordmark accentColor={colors.primaryHex} />
11193
</Link>
112-
<p className="m-0 mb-6 leading-[1.7] tracking-tight" style={{
113-
fontSize: "15px",
114-
fontWeight: 700,
115-
color: "var(--muted)",
116-
maxWidth: "320px"
117-
}}>
94+
<p
95+
className="m-0 mb-4 leading-[1.55] tracking-tight"
96+
style={{
97+
fontSize: "13px",
98+
fontWeight: 700,
99+
color: "var(--muted)",
100+
maxWidth: "420px"
101+
}}
102+
>
118103
{copy.description}
119104
</p>
120-
<div className="flex gap-3">
105+
<div className="flex gap-2">
121106
{socialLinks.map((social) => {
122107
const Icon = social.icon;
123108
return (
@@ -127,60 +112,49 @@ export function Footer() {
127112
target="_blank"
128113
rel="noopener noreferrer"
129114
aria-label={social.label === "Email" && isKorean ? "이메일" : social.label}
130-
className="flex h-10 w-10 items-center justify-center rounded-lg transition-all hover:scale-110"
115+
className="flex h-9 w-9 items-center justify-center rounded-lg transition-all hover:scale-110"
131116
style={{
132-
background: `${colors.primary}, 0.08)`,
133-
border: `1px solid ${colors.primary}, 0.22)`,
117+
background: tone(0.08),
118+
border: `1px solid ${tone(0.22)}`,
134119
color: colors.primaryHex
135120
}}
136121
>
137-
<Icon size={20} strokeWidth={2} />
122+
<Icon size={18} strokeWidth={2} />
138123
</a>
139124
);
140125
})}
141126
</div>
142127
</div>
143128

144129
<div>
145-
<h3 className="m-0 mb-4 tracking-tight" style={{ fontSize: "14px", fontWeight: 950, color: "var(--white)" }}>
146-
{copy.product}
147-
</h3>
148-
{renderLinks(footerLinks.product)}
149-
</div>
150-
151-
<div>
152-
<h3 className="m-0 mb-4 tracking-tight" style={{ fontSize: "14px", fontWeight: 950, color: "var(--white)" }}>
153-
{copy.company}
154-
</h3>
155-
{renderLinks(footerLinks.company)}
156-
</div>
157-
158-
<div>
159-
<h3 className="m-0 mb-4 tracking-tight" style={{ fontSize: "14px", fontWeight: 950, color: "var(--white)" }}>
160-
{copy.resources}
130+
<h3 className="m-0 mb-3 tracking-tight" style={{ fontSize: "13px", fontWeight: 950, color: "var(--white)" }}>
131+
{copy.navigation}
161132
</h3>
162-
{renderLinks(footerLinks.resources)}
133+
{renderLinks(footerLinks.navigation)}
163134
</div>
164135

165136
<div>
166-
<h3 className="m-0 mb-4 tracking-tight" style={{ fontSize: "14px", fontWeight: 950, color: "var(--white)" }}>
167-
{copy.legal}
137+
<h3 className="m-0 mb-3 tracking-tight" style={{ fontSize: "13px", fontWeight: 950, color: "var(--white)" }}>
138+
{copy.account}
168139
</h3>
169-
{renderLinks(footerLinks.legal)}
140+
{renderLinks(footerLinks.account)}
170141
</div>
171142
</div>
172143

173-
<div className="pt-8" style={{ borderTop: `1px solid ${colors.primary}, 0.15)` }}>
174-
<div className="flex flex-col items-center justify-between gap-4 md:flex-row">
175-
<p className="m-0 tracking-tight" style={{ fontSize: "13px", fontWeight: 700, color: "var(--muted)" }}>
144+
<div className="pt-5" style={{ borderTop: `1px solid ${tone(0.14)}` }}>
145+
<div className="flex flex-col items-center justify-between gap-3 md:flex-row">
146+
<p className="m-0 tracking-tight" style={{ fontSize: "12px", fontWeight: 700, color: "var(--muted)" }}>
176147
© {currentYear} CodeDock. {copy.rights}
177148
</p>
178-
<p className="m-0 flex items-center gap-2 tracking-tight" style={{
179-
fontSize: "13px",
180-
fontWeight: 700,
181-
color: "var(--muted)"
182-
}}>
183-
{copy.madeWith} <Heart size={16} strokeWidth={2} style={{ color: "#FF6B6B" }} fill="#FF6B6B" /> {copy.madeBy}
149+
<p
150+
className="m-0 flex items-center gap-2 tracking-tight"
151+
style={{
152+
fontSize: "12px",
153+
fontWeight: 700,
154+
color: "var(--muted)"
155+
}}
156+
>
157+
{copy.madeWith} <Heart size={14} strokeWidth={2} style={{ color: "#FF6B6B" }} fill="#FF6B6B" /> {copy.madeBy}
184158
</p>
185159
</div>
186160
</div>

0 commit comments

Comments
 (0)