Files
hanarang-dashboard/frontend/components/projects/ProjectCard.tsx
narang-ai 230d3847ef feat(redesign-v2): 미니멀 터미널 UI 전체 리디자인
- 디자인 시스템: #151515 배경, 1px 보더 카드, CSS vars, mono 포인트
- GlobalStyle/theme.ts v2 (DESIGN-SYSTEM.md 기반)
- 공통 컴포넌트 (ui/base.tsx): LabelMeta, BracketValue, Card, TechBar, Timeline 등
- Sidebar: [대시] 브라켓 네비 + 모바일 하단 탭바 (767px)
- LayoutShell: SidebarContext 제거, 단순화
- 대시보드 (/): SYS 상태 카드 4개 + ONGOING PROJECTS + ACTIVITY FEED
- 활동 로그 (/activities): 로그 테이블 + 필터 + 검색 + 페이지네이션 (신규)
- 설정 (/settings): 4섹션 Toggle/Bracket Input 그리드
- 자매 노드 관리 (/sisters): 3열 수평 레이아웃 (INFO/GRAPH/SYNC)
- 자매 상세 (/sisters/[name]): 간소화 + 터미널 스타일
- 조직도 (/org): 터미널 카드 트리 구조 + 레벨 색상
- 프로젝트 목록 (/projects): 새 라우트
- 프로젝트 상세 (/projects/[id]): Phase Timeline + Audit Log + Checklist
- FE 14 routes build 성공
2026-04-04 13:10:57 +09:00

116 lines
2.6 KiB
TypeScript

'use client';
import React from 'react';
import styled from 'styled-components';
import Link from 'next/link';
import ProgressBar from '../common/ProgressBar';
import { theme } from '@/styles/theme';
interface ProjectCardProps {
id: number;
name: string;
description: string | null;
status: string;
progress: number;
doneTasks: number;
totalTasks: number;
openPRs: number;
currentSprint: string | null;
}
const Card = styled(Link)`
display: block;
background: var(--bg-surface);
backdrop-filter: blur(12px);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 20px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
text-decoration: none;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
border-color: rgba(88,166,255,0.3);
}
`;
const Header = styled.div`
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
gap: 8px;
`;
const Name = styled.span`
font-size: 15px;
font-weight: 600;
color: var(--text-primary);
`;
const Meta = styled.div`
font-size: 12px;
color: var(--text-secondary);
margin-bottom: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
const Stats = styled.div`
display: flex;
gap: 16px;
margin-top: 12px;
`;
const Stat = styled.div`
font-size: 12px;
color: var(--text-secondary);
display: flex;
align-items: center;
gap: 4px;
`;
const ProgressLabel = styled.div`
display: flex;
justify-content: space-between;
margin-bottom: 6px;
`;
const ProgressText = styled.span`
font-size: 11px;
color: var(--text-secondary);
`;
const PRBadge = styled.span<{ $count: number }>`
font-size: 11px;
padding: 2px 7px;
border-radius: 4px;
background: ${({ $count }) => $count > 0 ? 'rgba(88,166,255,0.12)' : 'rgba(139,148,158,0.08)'};
color: ${({ $count }) => $count > 0 ? '#58A6FF' : 'var(--text-secondary)'};
font-weight: 600;
`;
export default function ProjectCard({
id, name, description, progress, doneTasks, totalTasks, openPRs, currentSprint,
}: ProjectCardProps) {
return (
<Card href={`/projects/${id}`}>
<Header>
<Name>{name}</Name>
<PRBadge $count={openPRs}>PR {openPRs}</PRBadge>
</Header>
{description && <Meta>{description}</Meta>}
{currentSprint && (
<Meta>📌 {currentSprint}</Meta>
)}
<ProgressLabel>
<ProgressText></ProgressText>
<ProgressText>{progress}% ({doneTasks}/{totalTasks})</ProgressText>
</ProgressLabel>
<ProgressBar value={progress} size="sm" />
</Card>
);
}