Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[design] 분석 차트 페이지 CSS 수정 #30

Merged
merged 4 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 5 additions & 1 deletion react-app/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import OnboardingPage from './pages/OnboardingPage';
import IdentifiedArticlesPage from './pages/IdentifiedArticlesPage';
import AnalysisPage from './pages/AnalysisPage';
import mockAnalysisDataList from './data/mockData' // Mock 데이터 import

export default function App() {
return (
<Router>
<Routes>
<Route path="/OnboardingPage" element={<OnboardingPage />} /> {/* 온보딩 페이지 라우팅 */}
<Route path="/IdentifiedArticlesPage" element={<IdentifiedArticlesPage />} /> {/* 판별 기사 목록 페이지 라우팅 */}
<Route path="/AnalysisPage" element={<AnalysisPage />} /> {/* 분석 차트 페이지 라우팅 */}
<Route
path="/AnalysisPage"
element={<AnalysisPage {...mockAnalysisDataList[0]} />} // 기본적으로 첫 번째 데이터 표시
/> {/* 분석 차트 페이지 라우팅 */}
</Routes>
</Router>
);
Expand Down
86 changes: 63 additions & 23 deletions react-app/src/components/layout/AnalysisPage.module.css
Original file line number Diff line number Diff line change
@@ -1,57 +1,97 @@
/* 페이지 전체 배경색을 연한 회색으로 설정 */
/* 글로벌 색상 변수 */
:root {
--color-background: #ebebeb;
--color-navy: #002b53;
--color-muted: #6c757d;
--color-white: #ffffff;
--color-border: #dee2e6;
}

/* 배경색 */
.bg-background {
background-color: #ebebeb;
background-color: var(--color-background);
}

/* 네비게이션 바의 배경색을 짙은 네이비로 설정 */
.bg-navy-900 {
background-color: #002b53;
.bg-navy {
background-color: var(--color-navy);
}

/* 텍스트 색상을 흰색으로 설정 */
/* 텍스트 색상 */
.text-white {
color: white;
color: var(--color-white);
}

/* 보조 텍스트(예: 설명글)의 색상을 회색 계열로 설정 */
.text-muted-foreground {
color: #000000;
.text-muted {
color: var(--color-muted);
}

/* 기본적인 테두리 스타일 정의 */
/* 테두리 */
.border {
border: 1px solid #dee2e6; /* 밝은 회색 테두리 */
border: 1px solid var(--color-border);
}

/* 요소의 모서리를 부드럽게 라운드 처리 */
/* 둥근 모서리 */
.rounded-lg {
border-radius: 0.5rem; /* 8px 반지름으로 둥글게 설정 */
border-radius: 0.5rem;
}

/* 컨테이너 최대 너비와 가운데 정렬을 설정 */
/* 레이아웃 */
.container {
max-width: 1200px; /* 컨테이너의 최대 너비 */
margin: 0 auto; /* 좌우 여백을 자동으로 설정해 가운데 정렬 */
max-width: 100%;
margin: 0 auto;
padding: 0 1rem;
}

/* 플렉스 박스 레이아웃 설정 */
@media (min-width: 768px) {
.container {
max-width: 720px;
}
}

@media (min-width: 1024px) {
.container {
max-width: 960px;
}
}

@media (min-width: 1200px) {
.container {
max-width: 1200px;
}
}

/* 유틸리티 클래스 */
.flex {
display: flex; /* 요소들을 플렉스 박스로 배치 */
display: flex;
}

.flex-row {
display: flex;
flex-direction: row;
}

.flex-col {
display: flex;
flex-direction: column;
}

.items-center {
align-items: center;
}

.justify-center {
justify-content: center;
}

/* 좌우 여백을 자동으로 설정해 가운데 정렬 */
.mx-auto {
margin-left: auto;
margin-right: auto;
}

/* 요소에 1rem(16px) 패딩을 추가 */
.p-4 {
padding: 1rem;
}

/* 요소의 아래쪽에 1rem(16px) 간격 추가 */
.mb-4 {
margin-bottom: 1rem;
}

217 changes: 123 additions & 94 deletions react-app/src/pages/AnalysisPage.jsx
Original file line number Diff line number Diff line change
@@ -1,111 +1,140 @@
// 뉴스 분석 페이지 구성
import { useParams } from 'react-router-dom'; // useParams 가져오기
import { mockAnalysisDataList } from '../data/mockData'; // Mock 데이터 가져오기
import { Button } from "../components/ui/Button";
import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
import { Link } from 'react-router-dom'; // Link 컴포넌트를 사용하기 위해 임포트
import '../components/layout/AnalysisPage.module.css';
import Navbar from '../components/layout/Navbar.jsx';

export default function AnalysisPage() {
return (
const AnalysisPage = () => {
const { id } = useParams(); // URL에서 id 파라미터 가져오기
const data = mockAnalysisDataList.find((item, index) => index + 1 === parseInt(id, 10)); // ID로 데이터 선택

if (!data) {
return <div>데이터를 찾을 수 없습니다.</div>; // ID가 유효하지 않을 때 처리
}

const { summary, accuracy, originalArticle } = data;

return (
<div className="min-h-screen bg-background">
{/* Navbar 사용 */}
<Navbar />

{/* 메인 콘텐츠 영역 */}
<main className="container mx-auto p-4">
<div className="grid gap-6 md:grid-cols-2">
{/* 왼쪽 섹션: 요약 및 분석 카드 */}
<div className="space-y-6">
{/* 요약 박스 */}
<Card>
<CardHeader>
<CardTitle>뉴스 요약</CardTitle>
</CardHeader>
<CardContent>
<div className="rounded-lg border bg-muted p-4 mb-4">
<h3 className="text-lg font-medium mb-4">
하마스 무장세력이 이스라엘 군인의 시신을 가자지구 거리로 끌고 다녀 양측의 긴장이 고조되었습니다.
</h3>
<div className="flex gap-2">
<Button size="sm" variant="secondary">
번역하기
</Button>
<Button size="sm" variant="secondary">
뉴스 요약
</Button>
</div>
</div>
</CardContent>
</Card>
{/* 요약 및 분석 섹션 */}
<AnalysisSummary summary={summary} />
<AnalysisResult accuracy={accuracy} />

{/* 원본 기사 섹션 */}
<OriginalArticle article={originalArticle} />
</div>
</main>
</div>
);
};

export default AnalysisPage;

{/* 분석 결과 카드 */}
<Card>
<CardHeader>
<CardTitle>Analysis Result</CardTitle>
</CardHeader>
<CardContent>
<div className="flex justify-center">
<div className="relative h-48 w-48">
<div className="absolute inset-0 flex items-center justify-center rounded-full border-8 border-primary/20">
<div className="text-center">
<div className="text-4xl font-bold">93%</div>
<div className="text-sm text-muted-foreground">Accuracy</div>
</div>
</div>
</div>
</div>
<div className="mt-6 flex justify-center gap-4">
<div className="flex items-center gap-2">
<div className="h-3 w-3 rounded-full bg-gray-300" />
<span className="text-sm">0-25%</span>
</div>
<div className="flex items-center gap-2">
<div className="h-3 w-3 rounded-full bg-blue-300" />
<span className="text-sm">26-50%</span>
</div>
<div className="flex items-center gap-2">
<div className="h-3 w-3 rounded-full bg-blue-500" />
<span className="text-sm">51-75%</span>
</div>
<div className="flex items-center gap-2">
<div className="h-3 w-3 rounded-full bg-blue-700" />
<span className="text-sm">76-100%</span>
</div>
</div>
</CardContent>
</Card>
// 요약 섹션 컴포넌트
const AnalysisSummary = ({ summary }) => {
return (
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>뉴스 요약</CardTitle>
</CardHeader>
<CardContent>
<div className="rounded-lg border bg-muted p-4 mb-4">
<h3 className="text-lg font-medium mb-4">{summary}</h3>
<div className="flex gap-2">
<Button size="sm" variant="secondary">
번역하기
</Button>
<Button size="sm" variant="secondary">
뉴스 요약
</Button>
</div>
</div>
</CardContent>
</Card>
</div>
);
};

{/* 오른쪽 섹션: 원본 기사 카드 */}
<Card>
<CardHeader>
<CardTitle>What are Israel&apos;s Iron Dome, David&apos;s Sling, and Arrow missile defenses?</CardTitle>
</CardHeader>
<CardContent>
{/* next/image 대신 img 태그 사용 */}
<img
alt="Israel missile defense system at night"
className="rounded-lg object-cover"
height={300}
src="/src/assets/images/fakenewsimg.png"
width={600}
/>
<div className="mt-4 space-y-4">
<p className="text-sm text-muted-foreground">
Israel uses its elaborate system of air defenses to counter hundreds of missiles and drones launched by Iran on Tuesday night.
</p>
<h3 className="font-medium">What are the different tiers of Israel&apos;s missile defence system?</h3>
<p className="text-sm text-muted-foreground">
Israel has several air defence systems, each one designed to intercept incoming missiles at different altitudes and distances...
</p>
<Link to="/read-more" className="text-blue-500 hover:underline">
Read More
</Link>
// 분석 결과 섹션 컴포넌트
const AnalysisResult = ({ accuracy }) => {
return (
<Card>
<CardHeader>
<CardTitle>Analysis Result</CardTitle>
</CardHeader>
<CardContent>
<div className="flex justify-center">
<div className="relative h-48 w-48">
<div className="absolute inset-0 flex items-center justify-center rounded-full border-8 border-primary/20">
<div className="text-center">
<div className="text-4xl font-bold">{accuracy}%</div>
<div className="text-sm text-muted-foreground">Accuracy</div>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
</main>
</div>
);
}
<div className="mt-6 flex justify-center gap-4">
<AccuracyLegend />
</div>
</CardContent>
</Card>
);
};

// 정확도 범례 컴포넌트
const AccuracyLegend = () => {
const legends = [
{ color: "bg-gray-300", label: "0-25%" },
{ color: "bg-blue-300", label: "26-50%" },
{ color: "bg-blue-500", label: "51-75%" },
{ color: "bg-blue-700", label: "76-100%" },
];

return (
<>
{legends.map((legend, index) => (
<div key={index} className="flex items-center gap-2">
<div className={`h-3 w-3 rounded-full ${legend.color}`} />
<span className="text-sm">{legend.label}</span>
</div>
))}
</>
);
};

// 원본 기사 섹션 컴포넌트
const OriginalArticle = ({ article }) => {
const { title, image, description, extraDetails, link } = article;

return (
<Card>
<CardHeader>
<CardTitle>{title}</CardTitle>
</CardHeader>
<CardContent>
<img
alt={title}
className="rounded-lg object-cover"
height={300}
src={image}
width={600}
/>
<div className="mt-4 space-y-4">
<p className="text-sm text-muted-foreground">{description}</p>
<h3 className="font-medium">{extraDetails}</h3>
<Link to={link} className="text-blue-500 hover:underline">
Read More
</Link>
</div>
</CardContent>
</Card>
);
};
Loading