From cab67c711a225bdaa4afde259c5fa1eacdef2cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EA=B2=BD?= Date: Tue, 3 Mar 2026 15:26:26 +0900 Subject: [PATCH] =?UTF-8?q?UI=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=B8=94?= =?UTF-8?q?=EB=9F=AC=EC=B2=98=EB=A6=AC=20=EC=A1=B0=EA=B1=B4=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.css | 19 ++--- src/index.tsx | 2 + src/pages/Dashboard/DashboardContent.tsx | 103 +++++++++++------------ 3 files changed, 59 insertions(+), 65 deletions(-) diff --git a/index.css b/index.css index bd00ee5..cee8f4c 100644 --- a/index.css +++ b/index.css @@ -5597,14 +5597,14 @@ } .dashboard-description { - font-size: 10px; + font-size: 15px; color: var(--color-text-gray-500); margin-top: 0.125rem; } @media (min-width: 640px) { .dashboard-description { - font-size: 10px; + font-size: 15px; } } @@ -5898,7 +5898,6 @@ justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; - margin-left: 2.5rem; } @media (min-width: 768px) { @@ -6096,16 +6095,19 @@ /* Mode Toggle */ .mode-toggle { display: flex; + flex-shrink: 0; border: 1px solid var(--color-border-gray-700); border-radius: var(--radius-full); overflow: hidden; } .mode-btn { + min-width: 48px; padding: 0.375rem 0.875rem; background-color: transparent; color: var(--color-text-gray-400); font-size: var(--text-sm); + white-space: nowrap; font-weight: 600; cursor: pointer; border: none; @@ -6503,23 +6505,16 @@ /* Stats Grid 8 Columns */ .stats-grid-8 { display: grid; - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.5rem; } @media (min-width: 640px) { .stats-grid-8 { - grid-template-columns: repeat(4, 1fr); gap: 0.75rem; } } -@media (min-width: 1024px) { - .stats-grid-8 { - grid-template-columns: repeat(8, 1fr); - } -} - /* Platform Metrics Grid 8 Columns */ .platform-metrics-grid-8 { display: grid; @@ -6758,7 +6753,7 @@ .audience-bar-label { font-size: var(--text-xs); color: var(--color-text-gray-400); - width: 40px; + width: 60px; flex-shrink: 0; } diff --git a/src/index.tsx b/src/index.tsx index 5f2500c..7152cf1 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,5 +11,7 @@ if (!rootElement) { const root = ReactDOM.createRoot(rootElement); root.render( + + ); diff --git a/src/pages/Dashboard/DashboardContent.tsx b/src/pages/Dashboard/DashboardContent.tsx index c3270d4..027e118 100755 --- a/src/pages/Dashboard/DashboardContent.tsx +++ b/src/pages/Dashboard/DashboardContent.tsx @@ -1,4 +1,3 @@ - import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { authenticatedFetch, API_URL } from '../../utils/api'; @@ -9,6 +8,7 @@ import { // 환경변수에서 테스트 모드 확인 const isTestPage = import.meta.env.VITE_IS_TESTPAGE === 'true'; + // ===================================================== // Types // ===================================================== @@ -132,7 +132,7 @@ const MOCK_TOP_CONTENT: TopContent[] = [ const MOCK_AUDIENCE_DATA: AudienceData = { ageGroups: [ - { label: '18-24', percentage: 12 }, + { label: '13-24', percentage: 12 }, { label: '25-34', percentage: 35 }, { label: '35-44', percentage: 28 }, { label: '45-54', percentage: 18 }, @@ -140,11 +140,11 @@ const MOCK_AUDIENCE_DATA: AudienceData = { ], gender: { male: 42, female: 58 }, topRegions: [ - { region: '서울', percentage: 32 }, - { region: '경기', percentage: 24 }, - { region: '부산', percentage: 12 }, - { region: '인천', percentage: 8 }, - { region: '대구', percentage: 6 }, + { region: '한국', percentage: 77 }, + { region: '일본', percentage: 5 }, + { region: '중국', percentage: 4 }, + { region: '미국', percentage: 2 }, + { region: '인도', percentage: 1 }, ], }; @@ -338,7 +338,7 @@ const YearOverYearChart: React.FC<{ tick={{ fill: 'rgba(255,255,255,0.4)', fontSize: 12 }} axisLine={false} tickLine={false} - interval={mode === 'day' ? 1 : 0} + interval={mode === 'day' ? 2 : 0} /> } /> = ({ onNavigate }) => { // API 데이터 우선 사용, 없거나 영상 없음(isEmptyState) 시 Mock 데이터로 폴백 const contentMetrics = (!isEmptyState && dashboardData?.contentMetrics?.length) ? dashboardData.contentMetrics : MOCK_CONTENT_METRICS; const topContent = (!isEmptyState && dashboardData?.topContent?.length) ? dashboardData.topContent : MOCK_TOP_CONTENT; - const hasRealAudienceData = !isEmptyState && !!dashboardData?.audienceData?.ageGroups?.length; + const hasRealAgeGroups = !isEmptyState && !!dashboardData?.audienceData?.ageGroups?.some(g => g.percentage > 0); + const hasRealGender = !isEmptyState && ((dashboardData?.audienceData?.gender?.male ?? 0) + (dashboardData?.audienceData?.gender?.female ?? 0)) > 0; + const hasRealTopRegions = !isEmptyState && !!dashboardData?.audienceData?.topRegions?.some(r => r.percentage > 0); + const hasRealAudienceData = hasRealAgeGroups && hasRealGender && hasRealTopRegions; const audienceData = hasRealAudienceData ? dashboardData!.audienceData : MOCK_AUDIENCE_DATA; // mode별 차트 데이터를 ChartDataPoint 통합 형식으로 변환 @@ -783,7 +786,7 @@ const DashboardContent: React.FC = ({ onNavigate }) => {

{t('dashboard.contentPerformance')}

-

ADO2에서 업로드한 영상의 통계가 표시됩니다.

+

ADO2에서 업로드한 최근 30개의 영상 통계가 표시됩니다.

- {audienceData ? ( -
-
- -
-

{t('dashboard.ageDistribution')}

- -
-
- -
-

{t('dashboard.genderDistribution')}

- -
-
- -
-

{t('dashboard.topRegions')}

- ({ label: r.region, percentage: r.percentage }))} delay={1400} /> -
-
-
- {dashboardData && !isEmptyState && !hasRealAudienceData && ( -
-
-

- 누적 데이터가 부족하여 실제 시청자 데이터가 없습니다. -

-
+
+
+ +
+

{t('dashboard.ageDistribution')}

+
- )} +
+ +
+

{t('dashboard.genderDistribution')}

+ +
+
+ +
+

{t('dashboard.topRegions')}

+ ({ label: r.region, percentage: r.percentage }))} delay={1400} /> +
+
- ) : ( -
- {t('dashboard.noData') || '이 기간에 데이터가 없습니다.'} -
- )} + {dashboardData && !isEmptyState && !hasRealAudienceData && ( +
+
+

+ 누적 데이터가 부족하여 실제 시청자 정보가 없습니다. +

+
+
+ )} +
{/* 개발자 모드 전용: mock 데이터 블러 해제 버튼 */}